Skip to content

Commit

Permalink
Merge pull request nfl#175 from Peleg/noscript
Browse files Browse the repository at this point in the history
adding noscript tag support
  • Loading branch information
cwelch5 authored Sep 21, 2016
2 parents 393d892 + e7bc6a1 commit b6329ad
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 3 deletions.
15 changes: 12 additions & 3 deletions src/Helmet.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const encodeSpecialCharacters = (str) => {
};

const getInnermostProperty = (propsList, property) => {
for(let i = propsList.length - 1; i >= 0; i--) {
for (let i = propsList.length - 1; i >= 0; i--) {
const props = propsList[i];

if (props[property]) {
Expand Down Expand Up @@ -279,7 +279,9 @@ const generateTagsAsString = (type, tags) => {

const tagContent = tag.innerHTML || tag.cssText || "";

return `<${type} ${HELMET_ATTRIBUTE}="true" ${attributeHtml}${type === TAG_NAMES.SCRIPT || type === TAG_NAMES.STYLE ? `>${tagContent}</${type}>` : `/>`}`;
const isSelfClosing = [TAG_NAMES.NOSCRIPT, TAG_NAMES.SCRIPT, TAG_NAMES.STYLE].indexOf(type) === -1;

return `<${type} ${HELMET_ATTRIBUTE}="true" ${attributeHtml}${isSelfClosing ? `/>` : `>${tagContent}</${type}>`}`;
}).join("");

return stringifiedMarkup;
Expand Down Expand Up @@ -347,13 +349,14 @@ const getMethodsForTag = (type, tags) => {
}
};

const mapStateOnServer = ({htmlAttributes, title, baseTag, metaTags, linkTags, scriptTags, styleTags}) => ({
const mapStateOnServer = ({htmlAttributes, title, baseTag, metaTags, linkTags, scriptTags, noscriptTags, styleTags}) => ({
htmlAttributes: getMethodsForTag(TAG_NAMES.HTML, htmlAttributes),
title: getMethodsForTag(TAG_NAMES.TITLE, title),
base: getMethodsForTag(TAG_NAMES.BASE, baseTag),
meta: getMethodsForTag(TAG_NAMES.META, metaTags),
link: getMethodsForTag(TAG_NAMES.LINK, linkTags),
script: getMethodsForTag(TAG_NAMES.SCRIPT, scriptTags),
noscript: getMethodsForTag(TAG_NAMES.NOSCRIPT, noscriptTags),
style: getMethodsForTag(TAG_NAMES.STYLE, styleTags)
});

Expand All @@ -369,6 +372,7 @@ const Helmet = (Component) => {
* @param {Array} meta: [{"name": "description", "content": "Test description"}]
* @param {Array} link: [{"rel": "canonical", "href": "http://mysite.com/example"}]
* @param {Array} script: [{"type": "text/javascript", "src": "http://mysite.com/js/test.js"}]
* @param {Array} noscript: [{"innerHTML": "<img src='http://mysite.com/js/test.js'"}]
* @param {Array} style: [{"type": "text/css", "cssText": "div{ display: block; color: blue; }"}]
* @param {Function} onChangeClientState: "(newState) => console.log(newState)"
*/
Expand All @@ -381,6 +385,7 @@ const Helmet = (Component) => {
meta: React.PropTypes.arrayOf(React.PropTypes.object),
link: React.PropTypes.arrayOf(React.PropTypes.object),
script: React.PropTypes.arrayOf(React.PropTypes.object),
noscript: React.PropTypes.arrayOf(React.PropTypes.object),
style: React.PropTypes.arrayOf(React.PropTypes.object),
onChangeClientState: React.PropTypes.func
}
Expand All @@ -406,6 +411,7 @@ const Helmet = (Component) => {
metaTags: [],
linkTags: [],
scriptTags: [],
noscriptTags: [],
styleTags: []
});
}
Expand Down Expand Up @@ -433,6 +439,7 @@ const reducePropsToState = (propsList) => ({
metaTags: getTagsFromPropsList(TAG_NAMES.META, [TAG_PROPERTIES.NAME, TAG_PROPERTIES.CHARSET, TAG_PROPERTIES.HTTPEQUIV, TAG_PROPERTIES.PROPERTY], propsList),
linkTags: getTagsFromPropsList(TAG_NAMES.LINK, [TAG_PROPERTIES.REL, TAG_PROPERTIES.HREF], propsList),
scriptTags: getTagsFromPropsList(TAG_NAMES.SCRIPT, [TAG_PROPERTIES.SRC, TAG_PROPERTIES.INNER_HTML], propsList),
noscriptTags: getTagsFromPropsList(TAG_NAMES.NOSCRIPT, [TAG_PROPERTIES.INNER_HTML], propsList),
styleTags: getTagsFromPropsList(TAG_NAMES.STYLE, [TAG_PROPERTIES.CSS_TEXT], propsList),
onChangeClientState: getOnChangeClientState(propsList)
});
Expand All @@ -445,6 +452,7 @@ const handleClientStateChange = (newState) => {
metaTags,
linkTags,
scriptTags,
noscriptTags,
styleTags,
onChangeClientState
} = newState;
Expand All @@ -458,6 +466,7 @@ const handleClientStateChange = (newState) => {
metaTags: updateTags(TAG_NAMES.META, metaTags),
linkTags: updateTags(TAG_NAMES.LINK, linkTags),
scriptTags: updateTags(TAG_NAMES.SCRIPT, scriptTags),
noscriptTags: updateTags(TAG_NAMES.NOSCRIPT, noscriptTags),
styleTags: updateTags(TAG_NAMES.STYLE, styleTags)
};

Expand Down
1 change: 1 addition & 0 deletions src/HelmetConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ export const TAG_NAMES = {
META: "meta",
LINK: "link",
SCRIPT: "script",
NOSCRIPT: "noscript",
STYLE: "style"
};

Expand Down
85 changes: 85 additions & 0 deletions src/test/HelmetTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,45 @@ describe("Helmet", () => {
});
});

describe("noscript tags", () => {
it("can update noscript tags", () => {
const noscriptInnerHTML = `<link rel="stylesheet" type="text/css" href="foo.css" />`;
ReactDOM.render(
<Helmet noscript={[{id: "bar", innerHTML: noscriptInnerHTML}]} />,
container
);

const existingTags = headElement.getElementsByTagName("noscript");

expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.equal(1);
expect(existingTags[0].innerHTML === noscriptInnerHTML && existingTags[0].id === "bar");
});

it("will clear all noscripts tags if none are specified", () => {
ReactDOM.render(<Helmet noscript={[{id: "bar"}]} />, container);

ReactDOM.render(<Helmet />, container);

const existingTags = headElement.querySelectorAll(`script[${HELMET_ATTRIBUTE}]`);

expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.equal(0);
});

it("tags without 'innerHTML' will not be accepted", () => {
ReactDOM.render(
<Helmet noscript={[{"property": "won't work"}]} />,
container
);

const existingTags = headElement.querySelectorAll(`noscript[${HELMET_ATTRIBUTE}]`);

expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.equal(0);
});
});

describe("style tags", () => {
it("can update style tags", () => {
const cssText1 = `
Expand Down Expand Up @@ -1254,6 +1293,11 @@ describe("Helmet", () => {
`<script ${HELMET_ATTRIBUTE}="true" src="http://localhost/test2.js" type="text/javascript"></script>`
].join("");

const stringifiedNoscriptTags = [
`<noscript ${HELMET_ATTRIBUTE}="true" id="foo"><link rel="stylesheet" type="text/css" href="/style.css" /></noscript>`,
`<noscript ${HELMET_ATTRIBUTE}="true" id="bar"><link rel="stylesheet" type="text/css" href="/style2.css" /></noscript>`
].join("");

const stringifiedStyleTags = [
`<style ${HELMET_ATTRIBUTE}="true" type="text/css">body {background-color: green;}</style>`,
`<style ${HELMET_ATTRIBUTE}="true" type="text/css">p {font-size: 12px;}</style>`
Expand Down Expand Up @@ -1480,6 +1524,47 @@ describe("Helmet", () => {
}</div>`);
});

it("will render noscript tags as React components", () => {
ReactDOM.render(
<Helmet
noscript={[
{id: "foo", innerHTML: '<link rel="stylesheet" type="text/css" href="/style.css" />'},
{id: "bar", innerHTML: '<link rel="stylesheet" type="text/css" href="/style2.css" />'}
]}
/>,
container
);

const head = Helmet.rewind();

expect(head.noscript).to.exist;
expect(head.noscript).to.respondTo("toComponent");

const noscriptComponent = head.noscript.toComponent();

expect(noscriptComponent)
.to.be.an("array")
.that.has.length.of(2);

noscriptComponent.forEach(noscript => {
expect(noscript)
.to.be.an("object")
.that.contains.property("type", "noscript");
});

const markup = ReactServer.renderToStaticMarkup(
<div>
{noscriptComponent}
</div>
);

expect(markup)
.to.be.a("string")
.that.equals(`<div>${
stringifiedNoscriptTags
}</div>`);
});

it("will render style tags as React components", () => {
ReactDOM.render(
<Helmet
Expand Down

0 comments on commit b6329ad

Please sign in to comment.