1 | import PropTypes from 'prop-types';
|
2 | import withSideEffect from 'react-side-effect';
|
3 | import isEqual from 'react-fast-compare';
|
4 | import React from 'react';
|
5 | import objectAssign from 'object-assign';
|
6 |
|
7 | var ATTRIBUTE_NAMES = {
|
8 | BODY: "bodyAttributes",
|
9 | HTML: "htmlAttributes",
|
10 | TITLE: "titleAttributes"
|
11 | };
|
12 |
|
13 | var TAG_NAMES = {
|
14 | BASE: "base",
|
15 | BODY: "body",
|
16 | HEAD: "head",
|
17 | HTML: "html",
|
18 | LINK: "link",
|
19 | META: "meta",
|
20 | NOSCRIPT: "noscript",
|
21 | SCRIPT: "script",
|
22 | STYLE: "style",
|
23 | TITLE: "title"
|
24 | };
|
25 |
|
26 | var VALID_TAG_NAMES = Object.keys(TAG_NAMES).map(function (name) {
|
27 | return TAG_NAMES[name];
|
28 | });
|
29 |
|
30 | var TAG_PROPERTIES = {
|
31 | CHARSET: "charset",
|
32 | CSS_TEXT: "cssText",
|
33 | HREF: "href",
|
34 | HTTPEQUIV: "http-equiv",
|
35 | INNER_HTML: "innerHTML",
|
36 | ITEM_PROP: "itemprop",
|
37 | NAME: "name",
|
38 | PROPERTY: "property",
|
39 | REL: "rel",
|
40 | SRC: "src",
|
41 | TARGET: "target"
|
42 | };
|
43 |
|
44 | var REACT_TAG_MAP = {
|
45 | accesskey: "accessKey",
|
46 | charset: "charSet",
|
47 | class: "className",
|
48 | contenteditable: "contentEditable",
|
49 | contextmenu: "contextMenu",
|
50 | "http-equiv": "httpEquiv",
|
51 | itemprop: "itemProp",
|
52 | tabindex: "tabIndex"
|
53 | };
|
54 |
|
55 | var HELMET_PROPS = {
|
56 | DEFAULT_TITLE: "defaultTitle",
|
57 | DEFER: "defer",
|
58 | ENCODE_SPECIAL_CHARACTERS: "encodeSpecialCharacters",
|
59 | ON_CHANGE_CLIENT_STATE: "onChangeClientState",
|
60 | TITLE_TEMPLATE: "titleTemplate"
|
61 | };
|
62 |
|
63 | var HTML_TAG_MAP = Object.keys(REACT_TAG_MAP).reduce(function (obj, key) {
|
64 | obj[REACT_TAG_MAP[key]] = key;
|
65 | return obj;
|
66 | }, {});
|
67 |
|
68 | var SELF_CLOSING_TAGS = [TAG_NAMES.NOSCRIPT, TAG_NAMES.SCRIPT, TAG_NAMES.STYLE];
|
69 |
|
70 | var HELMET_ATTRIBUTE = "data-react-helmet";
|
71 |
|
72 | var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) {
|
73 | return typeof obj;
|
74 | } : function (obj) {
|
75 | return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj;
|
76 | };
|
77 |
|
78 | var classCallCheck = function (instance, Constructor) {
|
79 | if (!(instance instanceof Constructor)) {
|
80 | throw new TypeError("Cannot call a class as a function");
|
81 | }
|
82 | };
|
83 |
|
84 | var createClass = function () {
|
85 | function defineProperties(target, props) {
|
86 | for (var i = 0; i < props.length; i++) {
|
87 | var descriptor = props[i];
|
88 | descriptor.enumerable = descriptor.enumerable || false;
|
89 | descriptor.configurable = true;
|
90 | if ("value" in descriptor) descriptor.writable = true;
|
91 | Object.defineProperty(target, descriptor.key, descriptor);
|
92 | }
|
93 | }
|
94 |
|
95 | return function (Constructor, protoProps, staticProps) {
|
96 | if (protoProps) defineProperties(Constructor.prototype, protoProps);
|
97 | if (staticProps) defineProperties(Constructor, staticProps);
|
98 | return Constructor;
|
99 | };
|
100 | }();
|
101 |
|
102 | var _extends = Object.assign || function (target) {
|
103 | for (var i = 1; i < arguments.length; i++) {
|
104 | var source = arguments[i];
|
105 |
|
106 | for (var key in source) {
|
107 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
108 | target[key] = source[key];
|
109 | }
|
110 | }
|
111 | }
|
112 |
|
113 | return target;
|
114 | };
|
115 |
|
116 | var inherits = function (subClass, superClass) {
|
117 | if (typeof superClass !== "function" && superClass !== null) {
|
118 | throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
|
119 | }
|
120 |
|
121 | subClass.prototype = Object.create(superClass && superClass.prototype, {
|
122 | constructor: {
|
123 | value: subClass,
|
124 | enumerable: false,
|
125 | writable: true,
|
126 | configurable: true
|
127 | }
|
128 | });
|
129 | if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
|
130 | };
|
131 |
|
132 | var objectWithoutProperties = function (obj, keys) {
|
133 | var target = {};
|
134 |
|
135 | for (var i in obj) {
|
136 | if (keys.indexOf(i) >= 0) continue;
|
137 | if (!Object.prototype.hasOwnProperty.call(obj, i)) continue;
|
138 | target[i] = obj[i];
|
139 | }
|
140 |
|
141 | return target;
|
142 | };
|
143 |
|
144 | var possibleConstructorReturn = function (self, call) {
|
145 | if (!self) {
|
146 | throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
|
147 | }
|
148 |
|
149 | return call && (typeof call === "object" || typeof call === "function") ? call : self;
|
150 | };
|
151 |
|
152 | var encodeSpecialCharacters = function encodeSpecialCharacters(str) {
|
153 | var encode = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
|
154 |
|
155 | if (encode === false) {
|
156 | return String(str);
|
157 | }
|
158 |
|
159 | return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
160 | };
|
161 |
|
162 | var getTitleFromPropsList = function getTitleFromPropsList(propsList) {
|
163 | var innermostTitle = getInnermostProperty(propsList, TAG_NAMES.TITLE);
|
164 | var innermostTemplate = getInnermostProperty(propsList, HELMET_PROPS.TITLE_TEMPLATE);
|
165 |
|
166 | if (innermostTemplate && innermostTitle) {
|
167 |
|
168 | return innermostTemplate.replace(/%s/g, function () {
|
169 | return Array.isArray(innermostTitle) ? innermostTitle.join("") : innermostTitle;
|
170 | });
|
171 | }
|
172 |
|
173 | var innermostDefaultTitle = getInnermostProperty(propsList, HELMET_PROPS.DEFAULT_TITLE);
|
174 |
|
175 | return innermostTitle || innermostDefaultTitle || undefined;
|
176 | };
|
177 |
|
178 | var getOnChangeClientState = function getOnChangeClientState(propsList) {
|
179 | return getInnermostProperty(propsList, HELMET_PROPS.ON_CHANGE_CLIENT_STATE) || function () {};
|
180 | };
|
181 |
|
182 | var getAttributesFromPropsList = function getAttributesFromPropsList(tagType, propsList) {
|
183 | return propsList.filter(function (props) {
|
184 | return typeof props[tagType] !== "undefined";
|
185 | }).map(function (props) {
|
186 | return props[tagType];
|
187 | }).reduce(function (tagAttrs, current) {
|
188 | return _extends({}, tagAttrs, current);
|
189 | }, {});
|
190 | };
|
191 |
|
192 | var getBaseTagFromPropsList = function getBaseTagFromPropsList(primaryAttributes, propsList) {
|
193 | return propsList.filter(function (props) {
|
194 | return typeof props[TAG_NAMES.BASE] !== "undefined";
|
195 | }).map(function (props) {
|
196 | return props[TAG_NAMES.BASE];
|
197 | }).reverse().reduce(function (innermostBaseTag, tag) {
|
198 | if (!innermostBaseTag.length) {
|
199 | var keys = Object.keys(tag);
|
200 |
|
201 | for (var i = 0; i < keys.length; i++) {
|
202 | var attributeKey = keys[i];
|
203 | var lowerCaseAttributeKey = attributeKey.toLowerCase();
|
204 |
|
205 | if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && tag[lowerCaseAttributeKey]) {
|
206 | return innermostBaseTag.concat(tag);
|
207 | }
|
208 | }
|
209 | }
|
210 |
|
211 | return innermostBaseTag;
|
212 | }, []);
|
213 | };
|
214 |
|
215 | var getTagsFromPropsList = function getTagsFromPropsList(tagName, primaryAttributes, propsList) {
|
216 |
|
217 | var approvedSeenTags = {};
|
218 |
|
219 | return propsList.filter(function (props) {
|
220 | if (Array.isArray(props[tagName])) {
|
221 | return true;
|
222 | }
|
223 | if (typeof props[tagName] !== "undefined") {
|
224 | warn("Helmet: " + tagName + " should be of type \"Array\". Instead found type \"" + _typeof(props[tagName]) + "\"");
|
225 | }
|
226 | return false;
|
227 | }).map(function (props) {
|
228 | return props[tagName];
|
229 | }).reverse().reduce(function (approvedTags, instanceTags) {
|
230 | var instanceSeenTags = {};
|
231 |
|
232 | instanceTags.filter(function (tag) {
|
233 | var primaryAttributeKey = void 0;
|
234 | var keys = Object.keys(tag);
|
235 | for (var i = 0; i < keys.length; i++) {
|
236 | var attributeKey = keys[i];
|
237 | var lowerCaseAttributeKey = attributeKey.toLowerCase();
|
238 |
|
239 |
|
240 | if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && !(primaryAttributeKey === TAG_PROPERTIES.REL && tag[primaryAttributeKey].toLowerCase() === "canonical") && !(lowerCaseAttributeKey === TAG_PROPERTIES.REL && tag[lowerCaseAttributeKey].toLowerCase() === "stylesheet")) {
|
241 | primaryAttributeKey = lowerCaseAttributeKey;
|
242 | }
|
243 |
|
244 | if (primaryAttributes.indexOf(attributeKey) !== -1 && (attributeKey === TAG_PROPERTIES.INNER_HTML || attributeKey === TAG_PROPERTIES.CSS_TEXT || attributeKey === TAG_PROPERTIES.ITEM_PROP)) {
|
245 | primaryAttributeKey = attributeKey;
|
246 | }
|
247 | }
|
248 |
|
249 | if (!primaryAttributeKey || !tag[primaryAttributeKey]) {
|
250 | return false;
|
251 | }
|
252 |
|
253 | var value = tag[primaryAttributeKey].toLowerCase();
|
254 |
|
255 | if (!approvedSeenTags[primaryAttributeKey]) {
|
256 | approvedSeenTags[primaryAttributeKey] = {};
|
257 | }
|
258 |
|
259 | if (!instanceSeenTags[primaryAttributeKey]) {
|
260 | instanceSeenTags[primaryAttributeKey] = {};
|
261 | }
|
262 |
|
263 | if (!approvedSeenTags[primaryAttributeKey][value]) {
|
264 | instanceSeenTags[primaryAttributeKey][value] = true;
|
265 | return true;
|
266 | }
|
267 |
|
268 | return false;
|
269 | }).reverse().forEach(function (tag) {
|
270 | return approvedTags.push(tag);
|
271 | });
|
272 |
|
273 |
|
274 | var keys = Object.keys(instanceSeenTags);
|
275 | for (var i = 0; i < keys.length; i++) {
|
276 | var attributeKey = keys[i];
|
277 | var tagUnion = objectAssign({}, approvedSeenTags[attributeKey], instanceSeenTags[attributeKey]);
|
278 |
|
279 | approvedSeenTags[attributeKey] = tagUnion;
|
280 | }
|
281 |
|
282 | return approvedTags;
|
283 | }, []).reverse();
|
284 | };
|
285 |
|
286 | var getInnermostProperty = function getInnermostProperty(propsList, property) {
|
287 | for (var i = propsList.length - 1; i >= 0; i--) {
|
288 | var props = propsList[i];
|
289 |
|
290 | if (props.hasOwnProperty(property)) {
|
291 | return props[property];
|
292 | }
|
293 | }
|
294 |
|
295 | return null;
|
296 | };
|
297 |
|
298 | var reducePropsToState = function reducePropsToState(propsList) {
|
299 | return {
|
300 | baseTag: getBaseTagFromPropsList([TAG_PROPERTIES.HREF, TAG_PROPERTIES.TARGET], propsList),
|
301 | bodyAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.BODY, propsList),
|
302 | defer: getInnermostProperty(propsList, HELMET_PROPS.DEFER),
|
303 | encode: getInnermostProperty(propsList, HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),
|
304 | htmlAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.HTML, propsList),
|
305 | linkTags: getTagsFromPropsList(TAG_NAMES.LINK, [TAG_PROPERTIES.REL, TAG_PROPERTIES.HREF], propsList),
|
306 | metaTags: getTagsFromPropsList(TAG_NAMES.META, [TAG_PROPERTIES.NAME, TAG_PROPERTIES.CHARSET, TAG_PROPERTIES.HTTPEQUIV, TAG_PROPERTIES.PROPERTY, TAG_PROPERTIES.ITEM_PROP], propsList),
|
307 | noscriptTags: getTagsFromPropsList(TAG_NAMES.NOSCRIPT, [TAG_PROPERTIES.INNER_HTML], propsList),
|
308 | onChangeClientState: getOnChangeClientState(propsList),
|
309 | scriptTags: getTagsFromPropsList(TAG_NAMES.SCRIPT, [TAG_PROPERTIES.SRC, TAG_PROPERTIES.INNER_HTML], propsList),
|
310 | styleTags: getTagsFromPropsList(TAG_NAMES.STYLE, [TAG_PROPERTIES.CSS_TEXT], propsList),
|
311 | title: getTitleFromPropsList(propsList),
|
312 | titleAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.TITLE, propsList)
|
313 | };
|
314 | };
|
315 |
|
316 | var rafPolyfill = function () {
|
317 | var clock = Date.now();
|
318 |
|
319 | return function (callback) {
|
320 | var currentTime = Date.now();
|
321 |
|
322 | if (currentTime - clock > 16) {
|
323 | clock = currentTime;
|
324 | callback(currentTime);
|
325 | } else {
|
326 | setTimeout(function () {
|
327 | rafPolyfill(callback);
|
328 | }, 0);
|
329 | }
|
330 | };
|
331 | }();
|
332 |
|
333 | var cafPolyfill = function cafPolyfill(id) {
|
334 | return clearTimeout(id);
|
335 | };
|
336 |
|
337 | var requestAnimationFrame = typeof window !== "undefined" ? window.requestAnimationFrame && window.requestAnimationFrame.bind(window) || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || rafPolyfill : global.requestAnimationFrame || rafPolyfill;
|
338 |
|
339 | var cancelAnimationFrame = typeof window !== "undefined" ? window.cancelAnimationFrame || window.webkitCancelAnimationFrame || window.mozCancelAnimationFrame || cafPolyfill : global.cancelAnimationFrame || cafPolyfill;
|
340 |
|
341 | var warn = function warn(msg) {
|
342 | return console && typeof console.warn === "function" && console.warn(msg);
|
343 | };
|
344 |
|
345 | var _helmetCallback = null;
|
346 |
|
347 | var handleClientStateChange = function handleClientStateChange(newState) {
|
348 | if (_helmetCallback) {
|
349 | cancelAnimationFrame(_helmetCallback);
|
350 | }
|
351 |
|
352 | if (newState.defer) {
|
353 | _helmetCallback = requestAnimationFrame(function () {
|
354 | commitTagChanges(newState, function () {
|
355 | _helmetCallback = null;
|
356 | });
|
357 | });
|
358 | } else {
|
359 | commitTagChanges(newState);
|
360 | _helmetCallback = null;
|
361 | }
|
362 | };
|
363 |
|
364 | var commitTagChanges = function commitTagChanges(newState, cb) {
|
365 | var baseTag = newState.baseTag,
|
366 | bodyAttributes = newState.bodyAttributes,
|
367 | htmlAttributes = newState.htmlAttributes,
|
368 | linkTags = newState.linkTags,
|
369 | metaTags = newState.metaTags,
|
370 | noscriptTags = newState.noscriptTags,
|
371 | onChangeClientState = newState.onChangeClientState,
|
372 | scriptTags = newState.scriptTags,
|
373 | styleTags = newState.styleTags,
|
374 | title = newState.title,
|
375 | titleAttributes = newState.titleAttributes;
|
376 |
|
377 | updateAttributes(TAG_NAMES.BODY, bodyAttributes);
|
378 | updateAttributes(TAG_NAMES.HTML, htmlAttributes);
|
379 |
|
380 | updateTitle(title, titleAttributes);
|
381 |
|
382 | var tagUpdates = {
|
383 | baseTag: updateTags(TAG_NAMES.BASE, baseTag),
|
384 | linkTags: updateTags(TAG_NAMES.LINK, linkTags),
|
385 | metaTags: updateTags(TAG_NAMES.META, metaTags),
|
386 | noscriptTags: updateTags(TAG_NAMES.NOSCRIPT, noscriptTags),
|
387 | scriptTags: updateTags(TAG_NAMES.SCRIPT, scriptTags),
|
388 | styleTags: updateTags(TAG_NAMES.STYLE, styleTags)
|
389 | };
|
390 |
|
391 | var addedTags = {};
|
392 | var removedTags = {};
|
393 |
|
394 | Object.keys(tagUpdates).forEach(function (tagType) {
|
395 | var _tagUpdates$tagType = tagUpdates[tagType],
|
396 | newTags = _tagUpdates$tagType.newTags,
|
397 | oldTags = _tagUpdates$tagType.oldTags;
|
398 |
|
399 |
|
400 | if (newTags.length) {
|
401 | addedTags[tagType] = newTags;
|
402 | }
|
403 | if (oldTags.length) {
|
404 | removedTags[tagType] = tagUpdates[tagType].oldTags;
|
405 | }
|
406 | });
|
407 |
|
408 | cb && cb();
|
409 |
|
410 | onChangeClientState(newState, addedTags, removedTags);
|
411 | };
|
412 |
|
413 | var flattenArray = function flattenArray(possibleArray) {
|
414 | return Array.isArray(possibleArray) ? possibleArray.join("") : possibleArray;
|
415 | };
|
416 |
|
417 | var updateTitle = function updateTitle(title, attributes) {
|
418 | if (typeof title !== "undefined" && document.title !== title) {
|
419 | document.title = flattenArray(title);
|
420 | }
|
421 |
|
422 | updateAttributes(TAG_NAMES.TITLE, attributes);
|
423 | };
|
424 |
|
425 | var updateAttributes = function updateAttributes(tagName, attributes) {
|
426 | var elementTag = document.getElementsByTagName(tagName)[0];
|
427 |
|
428 | if (!elementTag) {
|
429 | return;
|
430 | }
|
431 |
|
432 | var helmetAttributeString = elementTag.getAttribute(HELMET_ATTRIBUTE);
|
433 | var helmetAttributes = helmetAttributeString ? helmetAttributeString.split(",") : [];
|
434 | var attributesToRemove = [].concat(helmetAttributes);
|
435 | var attributeKeys = Object.keys(attributes);
|
436 |
|
437 | for (var i = 0; i < attributeKeys.length; i++) {
|
438 | var attribute = attributeKeys[i];
|
439 | var value = attributes[attribute] || "";
|
440 |
|
441 | if (elementTag.getAttribute(attribute) !== value) {
|
442 | elementTag.setAttribute(attribute, value);
|
443 | }
|
444 |
|
445 | if (helmetAttributes.indexOf(attribute) === -1) {
|
446 | helmetAttributes.push(attribute);
|
447 | }
|
448 |
|
449 | var indexToSave = attributesToRemove.indexOf(attribute);
|
450 | if (indexToSave !== -1) {
|
451 | attributesToRemove.splice(indexToSave, 1);
|
452 | }
|
453 | }
|
454 |
|
455 | for (var _i = attributesToRemove.length - 1; _i >= 0; _i--) {
|
456 | elementTag.removeAttribute(attributesToRemove[_i]);
|
457 | }
|
458 |
|
459 | if (helmetAttributes.length === attributesToRemove.length) {
|
460 | elementTag.removeAttribute(HELMET_ATTRIBUTE);
|
461 | } else if (elementTag.getAttribute(HELMET_ATTRIBUTE) !== attributeKeys.join(",")) {
|
462 | elementTag.setAttribute(HELMET_ATTRIBUTE, attributeKeys.join(","));
|
463 | }
|
464 | };
|
465 |
|
466 | var updateTags = function updateTags(type, tags) {
|
467 | var headElement = document.head || document.querySelector(TAG_NAMES.HEAD);
|
468 | var tagNodes = headElement.querySelectorAll(type + "[" + HELMET_ATTRIBUTE + "]");
|
469 | var oldTags = Array.prototype.slice.call(tagNodes);
|
470 | var newTags = [];
|
471 | var indexToDelete = void 0;
|
472 |
|
473 | if (tags && tags.length) {
|
474 | tags.forEach(function (tag) {
|
475 | var newElement = document.createElement(type);
|
476 |
|
477 | for (var attribute in tag) {
|
478 | if (tag.hasOwnProperty(attribute)) {
|
479 | if (attribute === TAG_PROPERTIES.INNER_HTML) {
|
480 | newElement.innerHTML = tag.innerHTML;
|
481 | } else if (attribute === TAG_PROPERTIES.CSS_TEXT) {
|
482 | if (newElement.styleSheet) {
|
483 | newElement.styleSheet.cssText = tag.cssText;
|
484 | } else {
|
485 | newElement.appendChild(document.createTextNode(tag.cssText));
|
486 | }
|
487 | } else {
|
488 | var value = typeof tag[attribute] === "undefined" ? "" : tag[attribute];
|
489 | newElement.setAttribute(attribute, value);
|
490 | }
|
491 | }
|
492 | }
|
493 |
|
494 | newElement.setAttribute(HELMET_ATTRIBUTE, "true");
|
495 |
|
496 |
|
497 | if (oldTags.some(function (existingTag, index) {
|
498 | indexToDelete = index;
|
499 | return newElement.isEqualNode(existingTag);
|
500 | })) {
|
501 | oldTags.splice(indexToDelete, 1);
|
502 | } else {
|
503 | newTags.push(newElement);
|
504 | }
|
505 | });
|
506 | }
|
507 |
|
508 | oldTags.forEach(function (tag) {
|
509 | return tag.parentNode.removeChild(tag);
|
510 | });
|
511 | newTags.forEach(function (tag) {
|
512 | return headElement.appendChild(tag);
|
513 | });
|
514 |
|
515 | return {
|
516 | oldTags: oldTags,
|
517 | newTags: newTags
|
518 | };
|
519 | };
|
520 |
|
521 | var generateElementAttributesAsString = function generateElementAttributesAsString(attributes) {
|
522 | return Object.keys(attributes).reduce(function (str, key) {
|
523 | var attr = typeof attributes[key] !== "undefined" ? key + "=\"" + attributes[key] + "\"" : "" + key;
|
524 | return str ? str + " " + attr : attr;
|
525 | }, "");
|
526 | };
|
527 |
|
528 | var generateTitleAsString = function generateTitleAsString(type, title, attributes, encode) {
|
529 | var attributeString = generateElementAttributesAsString(attributes);
|
530 | var flattenedTitle = flattenArray(title);
|
531 | return attributeString ? "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\" " + attributeString + ">" + encodeSpecialCharacters(flattenedTitle, encode) + "</" + type + ">" : "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\">" + encodeSpecialCharacters(flattenedTitle, encode) + "</" + type + ">";
|
532 | };
|
533 |
|
534 | var generateTagsAsString = function generateTagsAsString(type, tags, encode) {
|
535 | return tags.reduce(function (str, tag) {
|
536 | var attributeHtml = Object.keys(tag).filter(function (attribute) {
|
537 | return !(attribute === TAG_PROPERTIES.INNER_HTML || attribute === TAG_PROPERTIES.CSS_TEXT);
|
538 | }).reduce(function (string, attribute) {
|
539 | var attr = typeof tag[attribute] === "undefined" ? attribute : attribute + "=\"" + encodeSpecialCharacters(tag[attribute], encode) + "\"";
|
540 | return string ? string + " " + attr : attr;
|
541 | }, "");
|
542 |
|
543 | var tagContent = tag.innerHTML || tag.cssText || "";
|
544 |
|
545 | var isSelfClosing = SELF_CLOSING_TAGS.indexOf(type) === -1;
|
546 |
|
547 | return str + "<" + type + " " + HELMET_ATTRIBUTE + "=\"true\" " + attributeHtml + (isSelfClosing ? "/>" : ">" + tagContent + "</" + type + ">");
|
548 | }, "");
|
549 | };
|
550 |
|
551 | var convertElementAttributestoReactProps = function convertElementAttributestoReactProps(attributes) {
|
552 | var initProps = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
553 |
|
554 | return Object.keys(attributes).reduce(function (obj, key) {
|
555 | obj[REACT_TAG_MAP[key] || key] = attributes[key];
|
556 | return obj;
|
557 | }, initProps);
|
558 | };
|
559 |
|
560 | var convertReactPropstoHtmlAttributes = function convertReactPropstoHtmlAttributes(props) {
|
561 | var initAttributes = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
562 |
|
563 | return Object.keys(props).reduce(function (obj, key) {
|
564 | obj[HTML_TAG_MAP[key] || key] = props[key];
|
565 | return obj;
|
566 | }, initAttributes);
|
567 | };
|
568 |
|
569 | var generateTitleAsReactComponent = function generateTitleAsReactComponent(type, title, attributes) {
|
570 | var _initProps;
|
571 |
|
572 |
|
573 | var initProps = (_initProps = {
|
574 | key: title
|
575 | }, _initProps[HELMET_ATTRIBUTE] = true, _initProps);
|
576 | var props = convertElementAttributestoReactProps(attributes, initProps);
|
577 |
|
578 | return [React.createElement(TAG_NAMES.TITLE, props, title)];
|
579 | };
|
580 |
|
581 | var generateTagsAsReactComponent = function generateTagsAsReactComponent(type, tags) {
|
582 | return tags.map(function (tag, i) {
|
583 | var _mappedTag;
|
584 |
|
585 | var mappedTag = (_mappedTag = {
|
586 | key: i
|
587 | }, _mappedTag[HELMET_ATTRIBUTE] = true, _mappedTag);
|
588 |
|
589 | Object.keys(tag).forEach(function (attribute) {
|
590 | var mappedAttribute = REACT_TAG_MAP[attribute] || attribute;
|
591 |
|
592 | if (mappedAttribute === TAG_PROPERTIES.INNER_HTML || mappedAttribute === TAG_PROPERTIES.CSS_TEXT) {
|
593 | var content = tag.innerHTML || tag.cssText;
|
594 | mappedTag.dangerouslySetInnerHTML = { __html: content };
|
595 | } else {
|
596 | mappedTag[mappedAttribute] = tag[attribute];
|
597 | }
|
598 | });
|
599 |
|
600 | return React.createElement(type, mappedTag);
|
601 | });
|
602 | };
|
603 |
|
604 | var getMethodsForTag = function getMethodsForTag(type, tags, encode) {
|
605 | switch (type) {
|
606 | case TAG_NAMES.TITLE:
|
607 | return {
|
608 | toComponent: function toComponent() {
|
609 | return generateTitleAsReactComponent(type, tags.title, tags.titleAttributes, encode);
|
610 | },
|
611 | toString: function toString() {
|
612 | return generateTitleAsString(type, tags.title, tags.titleAttributes, encode);
|
613 | }
|
614 | };
|
615 | case ATTRIBUTE_NAMES.BODY:
|
616 | case ATTRIBUTE_NAMES.HTML:
|
617 | return {
|
618 | toComponent: function toComponent() {
|
619 | return convertElementAttributestoReactProps(tags);
|
620 | },
|
621 | toString: function toString() {
|
622 | return generateElementAttributesAsString(tags);
|
623 | }
|
624 | };
|
625 | default:
|
626 | return {
|
627 | toComponent: function toComponent() {
|
628 | return generateTagsAsReactComponent(type, tags);
|
629 | },
|
630 | toString: function toString() {
|
631 | return generateTagsAsString(type, tags, encode);
|
632 | }
|
633 | };
|
634 | }
|
635 | };
|
636 |
|
637 | var mapStateOnServer = function mapStateOnServer(_ref) {
|
638 | var baseTag = _ref.baseTag,
|
639 | bodyAttributes = _ref.bodyAttributes,
|
640 | encode = _ref.encode,
|
641 | htmlAttributes = _ref.htmlAttributes,
|
642 | linkTags = _ref.linkTags,
|
643 | metaTags = _ref.metaTags,
|
644 | noscriptTags = _ref.noscriptTags,
|
645 | scriptTags = _ref.scriptTags,
|
646 | styleTags = _ref.styleTags,
|
647 | _ref$title = _ref.title,
|
648 | title = _ref$title === undefined ? "" : _ref$title,
|
649 | titleAttributes = _ref.titleAttributes;
|
650 | return {
|
651 | base: getMethodsForTag(TAG_NAMES.BASE, baseTag, encode),
|
652 | bodyAttributes: getMethodsForTag(ATTRIBUTE_NAMES.BODY, bodyAttributes, encode),
|
653 | htmlAttributes: getMethodsForTag(ATTRIBUTE_NAMES.HTML, htmlAttributes, encode),
|
654 | link: getMethodsForTag(TAG_NAMES.LINK, linkTags, encode),
|
655 | meta: getMethodsForTag(TAG_NAMES.META, metaTags, encode),
|
656 | noscript: getMethodsForTag(TAG_NAMES.NOSCRIPT, noscriptTags, encode),
|
657 | script: getMethodsForTag(TAG_NAMES.SCRIPT, scriptTags, encode),
|
658 | style: getMethodsForTag(TAG_NAMES.STYLE, styleTags, encode),
|
659 | title: getMethodsForTag(TAG_NAMES.TITLE, { title: title, titleAttributes: titleAttributes }, encode)
|
660 | };
|
661 | };
|
662 |
|
663 | var Helmet = function Helmet(Component) {
|
664 | var _class, _temp;
|
665 |
|
666 | return _temp = _class = function (_React$Component) {
|
667 | inherits(HelmetWrapper, _React$Component);
|
668 |
|
669 | function HelmetWrapper() {
|
670 | classCallCheck(this, HelmetWrapper);
|
671 | return possibleConstructorReturn(this, _React$Component.apply(this, arguments));
|
672 | }
|
673 |
|
674 | HelmetWrapper.prototype.shouldComponentUpdate = function shouldComponentUpdate(nextProps) {
|
675 | return !isEqual(this.props, nextProps);
|
676 | };
|
677 |
|
678 | HelmetWrapper.prototype.mapNestedChildrenToProps = function mapNestedChildrenToProps(child, nestedChildren) {
|
679 | if (!nestedChildren) {
|
680 | return null;
|
681 | }
|
682 |
|
683 | switch (child.type) {
|
684 | case TAG_NAMES.SCRIPT:
|
685 | case TAG_NAMES.NOSCRIPT:
|
686 | return {
|
687 | innerHTML: nestedChildren
|
688 | };
|
689 |
|
690 | case TAG_NAMES.STYLE:
|
691 | return {
|
692 | cssText: nestedChildren
|
693 | };
|
694 | }
|
695 |
|
696 | throw new Error("<" + child.type + " /> elements are self-closing and can not contain children. Refer to our API for more information.");
|
697 | };
|
698 |
|
699 | HelmetWrapper.prototype.flattenArrayTypeChildren = function flattenArrayTypeChildren(_ref) {
|
700 | var _babelHelpers$extends;
|
701 |
|
702 | var child = _ref.child,
|
703 | arrayTypeChildren = _ref.arrayTypeChildren,
|
704 | newChildProps = _ref.newChildProps,
|
705 | nestedChildren = _ref.nestedChildren;
|
706 |
|
707 | return _extends({}, arrayTypeChildren, (_babelHelpers$extends = {}, _babelHelpers$extends[child.type] = [].concat(arrayTypeChildren[child.type] || [], [_extends({}, newChildProps, this.mapNestedChildrenToProps(child, nestedChildren))]), _babelHelpers$extends));
|
708 | };
|
709 |
|
710 | HelmetWrapper.prototype.mapObjectTypeChildren = function mapObjectTypeChildren(_ref2) {
|
711 | var _babelHelpers$extends2, _babelHelpers$extends3;
|
712 |
|
713 | var child = _ref2.child,
|
714 | newProps = _ref2.newProps,
|
715 | newChildProps = _ref2.newChildProps,
|
716 | nestedChildren = _ref2.nestedChildren;
|
717 |
|
718 | switch (child.type) {
|
719 | case TAG_NAMES.TITLE:
|
720 | return _extends({}, newProps, (_babelHelpers$extends2 = {}, _babelHelpers$extends2[child.type] = nestedChildren, _babelHelpers$extends2.titleAttributes = _extends({}, newChildProps), _babelHelpers$extends2));
|
721 |
|
722 | case TAG_NAMES.BODY:
|
723 | return _extends({}, newProps, {
|
724 | bodyAttributes: _extends({}, newChildProps)
|
725 | });
|
726 |
|
727 | case TAG_NAMES.HTML:
|
728 | return _extends({}, newProps, {
|
729 | htmlAttributes: _extends({}, newChildProps)
|
730 | });
|
731 | }
|
732 |
|
733 | return _extends({}, newProps, (_babelHelpers$extends3 = {}, _babelHelpers$extends3[child.type] = _extends({}, newChildProps), _babelHelpers$extends3));
|
734 | };
|
735 |
|
736 | HelmetWrapper.prototype.mapArrayTypeChildrenToProps = function mapArrayTypeChildrenToProps(arrayTypeChildren, newProps) {
|
737 | var newFlattenedProps = _extends({}, newProps);
|
738 |
|
739 | Object.keys(arrayTypeChildren).forEach(function (arrayChildName) {
|
740 | var _babelHelpers$extends4;
|
741 |
|
742 | newFlattenedProps = _extends({}, newFlattenedProps, (_babelHelpers$extends4 = {}, _babelHelpers$extends4[arrayChildName] = arrayTypeChildren[arrayChildName], _babelHelpers$extends4));
|
743 | });
|
744 |
|
745 | return newFlattenedProps;
|
746 | };
|
747 |
|
748 | HelmetWrapper.prototype.warnOnInvalidChildren = function warnOnInvalidChildren(child, nestedChildren) {
|
749 | if (process.env.NODE_ENV !== "production") {
|
750 | if (!VALID_TAG_NAMES.some(function (name) {
|
751 | return child.type === name;
|
752 | })) {
|
753 | if (typeof child.type === "function") {
|
754 | return warn("You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.");
|
755 | }
|
756 |
|
757 | return warn("Only elements types " + VALID_TAG_NAMES.join(", ") + " are allowed. Helmet does not support rendering <" + child.type + "> elements. Refer to our API for more information.");
|
758 | }
|
759 |
|
760 | if (nestedChildren && typeof nestedChildren !== "string" && (!Array.isArray(nestedChildren) || nestedChildren.some(function (nestedChild) {
|
761 | return typeof nestedChild !== "string";
|
762 | }))) {
|
763 | throw new Error("Helmet expects a string as a child of <" + child.type + ">. Did you forget to wrap your children in braces? ( <" + child.type + ">{``}</" + child.type + "> ) Refer to our API for more information.");
|
764 | }
|
765 | }
|
766 |
|
767 | return true;
|
768 | };
|
769 |
|
770 | HelmetWrapper.prototype.mapChildrenToProps = function mapChildrenToProps(children, newProps) {
|
771 | var _this2 = this;
|
772 |
|
773 | var arrayTypeChildren = {};
|
774 |
|
775 | React.Children.forEach(children, function (child) {
|
776 | if (!child || !child.props) {
|
777 | return;
|
778 | }
|
779 |
|
780 | var _child$props = child.props,
|
781 | nestedChildren = _child$props.children,
|
782 | childProps = objectWithoutProperties(_child$props, ["children"]);
|
783 |
|
784 | var newChildProps = convertReactPropstoHtmlAttributes(childProps);
|
785 |
|
786 | _this2.warnOnInvalidChildren(child, nestedChildren);
|
787 |
|
788 | switch (child.type) {
|
789 | case TAG_NAMES.LINK:
|
790 | case TAG_NAMES.META:
|
791 | case TAG_NAMES.NOSCRIPT:
|
792 | case TAG_NAMES.SCRIPT:
|
793 | case TAG_NAMES.STYLE:
|
794 | arrayTypeChildren = _this2.flattenArrayTypeChildren({
|
795 | child: child,
|
796 | arrayTypeChildren: arrayTypeChildren,
|
797 | newChildProps: newChildProps,
|
798 | nestedChildren: nestedChildren
|
799 | });
|
800 | break;
|
801 |
|
802 | default:
|
803 | newProps = _this2.mapObjectTypeChildren({
|
804 | child: child,
|
805 | newProps: newProps,
|
806 | newChildProps: newChildProps,
|
807 | nestedChildren: nestedChildren
|
808 | });
|
809 | break;
|
810 | }
|
811 | });
|
812 |
|
813 | newProps = this.mapArrayTypeChildrenToProps(arrayTypeChildren, newProps);
|
814 | return newProps;
|
815 | };
|
816 |
|
817 | HelmetWrapper.prototype.render = function render() {
|
818 | var _props = this.props,
|
819 | children = _props.children,
|
820 | props = objectWithoutProperties(_props, ["children"]);
|
821 |
|
822 | var newProps = _extends({}, props);
|
823 |
|
824 | if (children) {
|
825 | newProps = this.mapChildrenToProps(children, newProps);
|
826 | }
|
827 |
|
828 | return React.createElement(Component, newProps);
|
829 | };
|
830 |
|
831 | createClass(HelmetWrapper, null, [{
|
832 | key: "canUseDOM",
|
833 |
|
834 |
|
835 |
|
836 |
|
837 |
|
838 |
|
839 |
|
840 | |
841 |
|
842 |
|
843 |
|
844 |
|
845 |
|
846 |
|
847 |
|
848 |
|
849 |
|
850 |
|
851 |
|
852 |
|
853 |
|
854 |
|
855 |
|
856 |
|
857 | set: function set$$1(canUseDOM) {
|
858 | Component.canUseDOM = canUseDOM;
|
859 | }
|
860 | }]);
|
861 | return HelmetWrapper;
|
862 | }(React.Component), _class.propTypes = {
|
863 | base: PropTypes.object,
|
864 | bodyAttributes: PropTypes.object,
|
865 | children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
866 | defaultTitle: PropTypes.string,
|
867 | defer: PropTypes.bool,
|
868 | encodeSpecialCharacters: PropTypes.bool,
|
869 | htmlAttributes: PropTypes.object,
|
870 | link: PropTypes.arrayOf(PropTypes.object),
|
871 | meta: PropTypes.arrayOf(PropTypes.object),
|
872 | noscript: PropTypes.arrayOf(PropTypes.object),
|
873 | onChangeClientState: PropTypes.func,
|
874 | script: PropTypes.arrayOf(PropTypes.object),
|
875 | style: PropTypes.arrayOf(PropTypes.object),
|
876 | title: PropTypes.string,
|
877 | titleAttributes: PropTypes.object,
|
878 | titleTemplate: PropTypes.string
|
879 | }, _class.defaultProps = {
|
880 | defer: true,
|
881 | encodeSpecialCharacters: true
|
882 | }, _class.peek = Component.peek, _class.rewind = function () {
|
883 | var mappedState = Component.rewind();
|
884 | if (!mappedState) {
|
885 |
|
886 | mappedState = mapStateOnServer({
|
887 | baseTag: [],
|
888 | bodyAttributes: {},
|
889 | encodeSpecialCharacters: true,
|
890 | htmlAttributes: {},
|
891 | linkTags: [],
|
892 | metaTags: [],
|
893 | noscriptTags: [],
|
894 | scriptTags: [],
|
895 | styleTags: [],
|
896 | title: "",
|
897 | titleAttributes: {}
|
898 | });
|
899 | }
|
900 |
|
901 | return mappedState;
|
902 | }, _temp;
|
903 | };
|
904 |
|
905 | var NullComponent = function NullComponent() {
|
906 | return null;
|
907 | };
|
908 |
|
909 | var HelmetSideEffects = withSideEffect(reducePropsToState, handleClientStateChange, mapStateOnServer)(NullComponent);
|
910 |
|
911 | var HelmetExport = Helmet(HelmetSideEffects);
|
912 | HelmetExport.renderStatic = HelmetExport.rewind;
|
913 |
|
914 | export default HelmetExport;
|
915 | export { HelmetExport as Helmet };
|