Skip to content

Commit

Permalink
added onerror attribute for <link> tag
Browse files Browse the repository at this point in the history
  • Loading branch information
kesava committed Oct 12, 2017
1 parent 99e4554 commit 04fe452
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 56 deletions.
2 changes: 1 addition & 1 deletion src/Helmet.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Helmet = Component =>
* @param {Boolean} defer: true
* @param {Boolean} encodeSpecialCharacters: true
* @param {Object} htmlAttributes: {"lang": "en", "amp": undefined}
* @param {Array} link: [{"rel": "canonical", "href": "http://mysite.com/example", "onLoad": "functionCall()"}]
* @param {Array} link: [{"rel": "canonical", "href": "http://mysite.com/example", "onLoad": "functionCall()", "onError": "functionCall()"}]
* @param {Array} meta: [{"name": "description", "content": "Test description"}]
* @param {Array} noscript: [{"innerHTML": "<img src='http://mysite.com/js/test.js'"}]
* @param {Function} onChangeClientState: "(newState) => console.log(newState)"
Expand Down
3 changes: 2 additions & 1 deletion src/HelmetConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export const TAG_PROPERTIES = {
PROPERTY: "property",
REL: "rel",
SRC: "src",
ONLOAD: "onload"
ONLOAD: "onload",
ONERROR: "onerror"
};

export const REACT_TAG_MAP = {
Expand Down
48 changes: 29 additions & 19 deletions src/HelmetUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,12 @@ const reducePropsToState = propsList => ({
htmlAttributes: getAttributesFromPropsList(ATTRIBUTE_NAMES.HTML, propsList),
linkTags: getTagsFromPropsList(
TAG_NAMES.LINK,
[TAG_PROPERTIES.REL, TAG_PROPERTIES.HREF, TAG_PROPERTIES.ONLOAD],
[
TAG_PROPERTIES.REL,
TAG_PROPERTIES.HREF,
TAG_PROPERTIES.ONLOAD,
TAG_PROPERTIES.ONERROR
],
propsList
),
metaTags: getTagsFromPropsList(
Expand Down Expand Up @@ -267,19 +272,21 @@ const rafPolyfill = (() => {

const cafPolyfill = (id: string | number) => clearTimeout(id);

const requestAnimationFrame = typeof window !== "undefined"
? window.requestAnimationFrame ||
const requestAnimationFrame =
typeof window !== "undefined"
? window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
rafPolyfill
: global.requestAnimationFrame || rafPolyfill;
: global.requestAnimationFrame || rafPolyfill;

const cancelAnimationFrame = typeof window !== "undefined"
? window.cancelAnimationFrame ||
const cancelAnimationFrame =
typeof window !== "undefined"
? window.cancelAnimationFrame ||
window.webkitCancelAnimationFrame ||
window.mozCancelAnimationFrame ||
cafPolyfill
: global.cancelAnimationFrame || cafPolyfill;
: global.cancelAnimationFrame || cafPolyfill;

const warn = msg => {
return console && typeof console.warn === "function" && console.warn(msg);
Expand Down Expand Up @@ -436,9 +443,10 @@ const updateTags = (type, tags) => {
);
}
} else {
const value = typeof tag[attribute] === "undefined"
? ""
: tag[attribute];
const value =
typeof tag[attribute] === "undefined"
? ""
: tag[attribute];
newElement.setAttribute(attribute, value);
}
}
Expand Down Expand Up @@ -471,9 +479,10 @@ const updateTags = (type, tags) => {

const generateElementAttributesAsString = attributes =>
Object.keys(attributes).reduce((str, key) => {
const attr = typeof attributes[key] !== "undefined"
? `${key}="${attributes[key]}"`
: `${key}`;
const attr =
typeof attributes[key] !== "undefined"
? `${key}="${attributes[key]}"`
: `${key}`;
return str ? `${str} ${attr}` : attr;
}, "");

Expand Down Expand Up @@ -502,12 +511,13 @@ const generateTagsAsString = (type, tags, encode) =>
)
)
.reduce((string, attribute) => {
const attr = typeof tag[attribute] === "undefined"
? attribute
: `${attribute}="${encodeSpecialCharacters(
tag[attribute],
encode
)}"`;
const attr =
typeof tag[attribute] === "undefined"
? attribute
: `${attribute}="${encodeSpecialCharacters(
tag[attribute],
encode
)}"`;
return string ? `${string} ${attr}` : attr;
}, "");

Expand Down
124 changes: 89 additions & 35 deletions test/HelmetDeclarativeTest.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,9 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet>
<title>Title: {someValue}</title>
<title>
Title: {someValue}
</title>
</Helmet>,
container
);
Expand Down Expand Up @@ -247,7 +249,9 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet titleTemplate={"This is a %s"}>
<title>{dollarTitle}</title>
<title>
{dollarTitle}
</title>
</Helmet>,
container
);
Expand All @@ -266,7 +270,9 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet>
<title>{chineseTitle}</title>
<title>
{chineseTitle}
</title>
</Helmet>,
container
);
Expand Down Expand Up @@ -326,7 +332,7 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet>
<title>{" "}</title>
<title />
<meta name="keywords" content="stuff" />
</Helmet>,
container
Expand Down Expand Up @@ -2059,46 +2065,78 @@ describe("Helmet - Declarative API", () => {
});
});

it("renders tag when onload attribute is present", (done) => {
it("renders tag when onload attribute is present", done => {
ReactDOM.render(
<Helmet>
<link onLoad="functionCall()" rel="stylesheet" media="all" type="text/css" href="http://localhost/critical-style.css" />
<link onLoad="if(media!='all')media='all'" rel="stylesheet" media="none" type="text/css" href="http://localhost/non-critical-style.css" />
<link
onLoad="functionCall()"
onError="handleErrorFunc()"
rel="stylesheet"
media="all"
type="text/css"
href="http://localhost/critical-style.css"
/>
<link
onLoad="if(media!='all')media='all'"
rel="stylesheet"
media="none"
type="text/css"
href="http://localhost/non-critical-style.css"
/>
</Helmet>,
container
);

requestIdleCallback(() => {
const tagNodes = headElement.querySelectorAll(`link[${HELMET_ATTRIBUTE}]`);
const tagNodes = headElement.querySelectorAll(
`link[${HELMET_ATTRIBUTE}]`
);
const existingTags = Array.prototype.slice.call(tagNodes);
const firstTag = existingTags[0];

expect(existingTags).to.not.equal(undefined);
expect(existingTags.length).to.be.equal(2);

expect(existingTags)
.to.have.deep.property("[0]")
expect(existingTags).to.have.deep
.property("[0]")
.that.is.an.instanceof(Element);
expect(firstTag).to.have.property("getAttribute");
expect(firstTag.getAttribute("rel")).to.equal("stylesheet");
expect(firstTag.getAttribute("media")).to.equal("all");
expect(firstTag.getAttribute("type")).to.equal("text/css");
expect(firstTag.getAttribute("onload")).to.equal("functionCall()");
expect(firstTag.getAttribute("href")).to.equal("http://localhost/critical-style.css");
expect(firstTag.outerHTML).to.equal(`<link onload="functionCall()" rel="stylesheet" media="all" type="text/css" href="http://localhost/critical-style.css" ${HELMET_ATTRIBUTE}="true">`);
expect(firstTag.getAttribute("onload")).to.equal(
"functionCall()"
);
expect(firstTag.getAttribute("onerror")).to.equal(
"handleErrorFunc()"
);
expect(firstTag.getAttribute("href")).to.equal(
"http://localhost/critical-style.css"
);
expect(firstTag.outerHTML).to.equal(
`<link onload="functionCall()" onerror="handleErrorFunc()" rel="stylesheet" media="all" type="text/css" href="http://localhost/critical-style.css" ${HELMET_ATTRIBUTE}="true">`
);

const secondTag = existingTags[1];

expect(existingTags)
.to.have.deep.property("[1]")
expect(existingTags).to.have.deep
.property("[1]")
.that.is.an.instanceof(Element);
expect(secondTag).to.have.property("getAttribute");
expect(secondTag.getAttribute("rel")).to.equal("stylesheet");
expect(secondTag.getAttribute("rel")).to.equal(
"stylesheet"
);
expect(secondTag.getAttribute("media")).to.equal("none");
expect(secondTag.getAttribute("type")).to.equal("text/css");
expect(secondTag.getAttribute("onload")).to.equal("if(media!='all')media='all'");
expect(secondTag.getAttribute("href")).to.equal("http://localhost/non-critical-style.css");
expect(secondTag.outerHTML).to.equal(`<link onload="if(media!='all')media='all'" rel="stylesheet" media="none" type="text/css" href="http://localhost/non-critical-style.css" ${HELMET_ATTRIBUTE}="true">`);
expect(secondTag.getAttribute("onload")).to.equal(
"if(media!='all')media='all'"
);
expect(secondTag.getAttribute("href")).to.equal(
"http://localhost/non-critical-style.css"
);
expect(secondTag.outerHTML).to.equal(
`<link onload="if(media!='all')media='all'" rel="stylesheet" media="none" type="text/css" href="http://localhost/non-critical-style.css" ${HELMET_ATTRIBUTE}="true">`
);

done();
});
Expand Down Expand Up @@ -2338,7 +2376,9 @@ describe("Helmet - Declarative API", () => {
const noscriptInnerHTML = `<link rel="stylesheet" type="text/css" href="foo.css" />`;
ReactDOM.render(
<Helmet>
<noscript id="bar">{noscriptInnerHTML}</noscript>
<noscript id="bar">
{noscriptInnerHTML}
</noscript>
</Helmet>,
container
);
Expand Down Expand Up @@ -2406,7 +2446,9 @@ describe("Helmet - Declarative API", () => {
it("does not render tag when primary attribute is null", done => {
ReactDOM.render(
<Helmet>
<noscript>{undefined}</noscript>
<noscript>
{undefined}
</noscript>
</Helmet>,
container
);
Expand Down Expand Up @@ -2438,8 +2480,12 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet>
<style type="text/css">{cssText1}</style>
<style>{cssText2}</style>
<style type="text/css">
{cssText1}
</style>
<style>
{cssText2}
</style>
</Helmet>,
container
);
Expand Down Expand Up @@ -2484,7 +2530,9 @@ describe("Helmet - Declarative API", () => {
`;
ReactDOM.render(
<Helmet>
<style type="text/css">{cssText}</style>
<style type="text/css">
{cssText}
</style>
</Helmet>,
container
);
Expand Down Expand Up @@ -2528,7 +2576,9 @@ describe("Helmet - Declarative API", () => {
it("does not render tag when primary attribute is null", done => {
ReactDOM.render(
<Helmet>
<style>{undefined}</style>
<style>
{undefined}
</style>
</Helmet>,
container
);
Expand Down Expand Up @@ -2559,14 +2609,10 @@ describe("Helmet - Declarative API", () => {
ReactDOM.render(
<div>
<Helmet defer={false}>
<script>
window.__spy__(1)
</script>
<script>window.__spy__(1)</script>
</Helmet>
<Helmet>
<script>
window.__spy__(2)
</script>
<script>window.__spy__(2)</script>
</Helmet>
</div>,
container
Expand Down Expand Up @@ -2652,7 +2698,9 @@ describe("Helmet - Declarative API", () => {
it("opts out of string encoding", () => {
ReactDOM.render(
<Helmet encodeSpecialCharacters={false}>
<title>{"This is text and & and '."}</title>
<title>
{"This is text and & and '."}
</title>
</Helmet>,
container
);
Expand Down Expand Up @@ -2956,7 +3004,9 @@ describe("Helmet - Declarative API", () => {
it("renders title tag as string", () => {
ReactDOM.render(
<Helmet>
<title>{"Dangerous <script> include"}</title>
<title>
{"Dangerous <script> include"}
</title>
</Helmet>,
container
);
Expand All @@ -2976,7 +3026,9 @@ describe("Helmet - Declarative API", () => {

ReactDOM.render(
<Helmet>
<title>Title: {someValue}</title>
<title>
Title: {someValue}
</title>
</Helmet>,
container
);
Expand Down Expand Up @@ -3211,7 +3263,9 @@ describe("Helmet - Declarative API", () => {
ReactDOM.render(
<div>
<Helmet>
<title>{chineseTitle}</title>
<title>
{chineseTitle}
</title>
</Helmet>
</div>,
container
Expand Down

0 comments on commit 04fe452

Please sign in to comment.