From 5a548bf924a06da16d77d48478ce5725f20858de Mon Sep 17 00:00:00 2001 From: Kesava Mallela Date: Thu, 12 Oct 2017 10:44:27 -0700 Subject: [PATCH] added onerror attribute for tag --- src/Helmet.js | 2 +- src/HelmetConstants.js | 3 +- src/HelmetUtils.js | 48 +++++++------ test/HelmetDeclarativeTest.js | 124 ++++++++++++++++++++++++---------- 4 files changed, 121 insertions(+), 56 deletions(-) diff --git a/src/Helmet.js b/src/Helmet.js index 12fd861c..9b982788 100644 --- a/src/Helmet.js +++ b/src/Helmet.js @@ -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": " console.log(newState)" diff --git a/src/HelmetConstants.js b/src/HelmetConstants.js index 042e2cd7..56611655 100644 --- a/src/HelmetConstants.js +++ b/src/HelmetConstants.js @@ -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 = { diff --git a/src/HelmetUtils.js b/src/HelmetUtils.js index 4b26d129..73738fb7 100644 --- a/src/HelmetUtils.js +++ b/src/HelmetUtils.js @@ -217,7 +217,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( @@ -273,19 +278,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); @@ -442,9 +449,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); } } @@ -477,9 +485,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; }, ""); @@ -508,12 +517,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; }, ""); diff --git a/test/HelmetDeclarativeTest.js b/test/HelmetDeclarativeTest.js index f9364cf9..1ec92b3c 100644 --- a/test/HelmetDeclarativeTest.js +++ b/test/HelmetDeclarativeTest.js @@ -50,7 +50,9 @@ describe("Helmet - Declarative API", () => { ReactDOM.render( - Title: {someValue} + + Title: {someValue} + , container ); @@ -247,7 +249,9 @@ describe("Helmet - Declarative API", () => { ReactDOM.render( - {dollarTitle} + + {dollarTitle} + , container ); @@ -281,7 +285,9 @@ describe("Helmet - Declarative API", () => { ReactDOM.render( - {chineseTitle} + + {chineseTitle} + , container ); @@ -341,7 +347,7 @@ describe("Helmet - Declarative API", () => { ReactDOM.render( - {" "} + <meta name="keywords" content="stuff" /> </Helmet>, container @@ -2074,46 +2080,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(); }); @@ -2353,7 +2391,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 ); @@ -2421,7 +2461,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 ); @@ -2453,8 +2495,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 ); @@ -2499,7 +2545,9 @@ describe("Helmet - Declarative API", () => { `; ReactDOM.render( <Helmet> - <style type="text/css">{cssText}</style> + <style type="text/css"> + {cssText} + </style> </Helmet>, container ); @@ -2543,7 +2591,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 ); @@ -2574,14 +2624,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 @@ -2667,7 +2713,9 @@ describe("Helmet - Declarative API", () => { it("opts out of string encoding", () => { ReactDOM.render( <Helmet encodeSpecialCharacters={false}> - <title>{"This is text and & and '."} + + {"This is text and & and '."} + , container ); @@ -2971,7 +3019,9 @@ describe("Helmet - Declarative API", () => { it("renders title tag as string", () => { ReactDOM.render( - {"Dangerous <script> include"} + + {"Dangerous <script> include"} + , container ); @@ -2991,7 +3041,9 @@ describe("Helmet - Declarative API", () => { ReactDOM.render( - Title: {someValue} + + Title: {someValue} + , container ); @@ -3226,7 +3278,9 @@ describe("Helmet - Declarative API", () => { ReactDOM.render(
- {chineseTitle} + + {chineseTitle} +
, container