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