react-document-meta
Advanced tools
Comparing version 2.0.3 to 2.1.0
@@ -19,3 +19,3 @@ 'use strict'; | ||
var _utils = require('../utils'); | ||
var _dom = require('../dom'); | ||
@@ -49,3 +49,3 @@ var _testUtils = require('./test-utils'); | ||
_2.default.canUseDOM = true; | ||
(0, _utils.removeDocumentMeta)(); | ||
(0, _dom.removeDocumentMeta)(); | ||
_reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement(_2.default, DOC_META)); | ||
@@ -71,3 +71,3 @@ }); | ||
it('should render normal meta tags, eg. <meta name="..." content="...">', function () { | ||
Object.keys(DOC_META.meta.name).reduce(function (name) { | ||
Object.keys(DOC_META.meta.name).forEach(function (name) { | ||
_assert2.default.strictEqual((0, _testUtils.getAttr)('meta[name=' + name + ']', 'content'), DOC_META.meta.name[name], '<meta name="' + name + '" ... /> has not been rendered correctly'); | ||
@@ -78,10 +78,32 @@ }); | ||
it('should render normal link tags, eg. <link rel="..." href="...">', function () { | ||
Object.keys(DOC_META.link.rel).reduce(function (rel) { | ||
Object.keys(DOC_META.link.rel).forEach(function (rel) { | ||
var values = Array.isArray(DOC_META.link.rel[rel]) ? DOC_META.link.rel[rel] : [DOC_META.link.rel[rel]]; | ||
var idx = 0; | ||
var elements = (0, _testUtils.getElements)('link[rel=' + rel + ']'); | ||
elements.forEach(function (element, idx) { | ||
_assert2.default.strictEqual(element.getAttribute('content'), values[idx], '<link rel="' + rel + '" ... /> has not been rendered correctly'); | ||
}); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = elements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var element = _step.value; | ||
_assert2.default.strictEqual(element.getAttribute('href'), values[idx++], '<link rel="' + rel + '" ... /> has not been rendered correctly'); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
}); |
@@ -21,3 +21,3 @@ 'use strict'; | ||
var _utils = require('../utils'); | ||
var _dom = require('../dom'); | ||
@@ -65,3 +65,3 @@ var _testUtils = require('./test-utils'); | ||
_2.default.canUseDOM = true; | ||
(0, _utils.removeDocumentMeta)(); | ||
(0, _dom.removeDocumentMeta)(); | ||
_reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( | ||
@@ -79,11 +79,11 @@ 'div', | ||
it('should render document.title / <title> according to the title-attr', function () { | ||
it('should render document.title / <title> according to the nested title-prop', function () { | ||
_assert2.default.strictEqual(document.title, DOC_META_NESTED.title); | ||
}); | ||
it('should render <meta name="description" content="..."> according to the description-attr', function () { | ||
it('should render <meta name="description" content="..."> according to the nested description-prop', function () { | ||
_assert2.default.strictEqual((0, _testUtils.getAttr)('meta[name=description]', 'content'), DOC_META_NESTED.description); | ||
}); | ||
it('should render <link rel="canonical" href="..." according to the canonical-attr', function () { | ||
it('should render <link rel="canonical" href="..." according to the nested canonical-prop', function () { | ||
_assert2.default.strictEqual((0, _testUtils.getAttr)('link[rel=canonical]', 'href'), DOC_META_NESTED.canonical); | ||
@@ -97,3 +97,3 @@ }); | ||
it('should render normal meta tags, eg. <meta name="..." content="...">', function () { | ||
Object.keys(DOC_META.meta.name).reduce(function (name) { | ||
Object.keys(DOC_META.meta.name).forEach(function (name) { | ||
var value = DOC_META_NESTED.meta.name.hasOwnProperty(name) ? DOC_META_NESTED.meta.name[name] : DOC_META.meta.name[name]; | ||
@@ -105,11 +105,88 @@ _assert2.default.strictEqual((0, _testUtils.getAttr)('meta[name=' + name + ']', 'content'), value, '<meta name="' + name + '" ... /> has not been rendered correctly'); | ||
it('should render normal link tags, eg. <link rel="..." href="...">', function () { | ||
Object.keys(DOC_META.link.rel).reduce(function (rel) { | ||
Object.keys(DOC_META.link.rel).forEach(function (rel) { | ||
var value = DOC_META_NESTED.link.rel.hasOwnProperty(rel) ? DOC_META_NESTED.link.rel[rel] : DOC_META.link.rel[rel]; | ||
var values = Array.isArray(value) ? value : [value]; | ||
var idx = 0; | ||
var elements = (0, _testUtils.getElements)('link[rel=' + rel + ']'); | ||
elements.forEach(function (element, idx) { | ||
_assert2.default.strictEqual(element.getAttribute('content'), values[idx], '<link rel="' + rel + '" ... /> has not been rendered correctly'); | ||
}); | ||
var _iteratorNormalCompletion = true; | ||
var _didIteratorError = false; | ||
var _iteratorError = undefined; | ||
try { | ||
for (var _iterator = elements[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { | ||
var element = _step.value; | ||
_assert2.default.strictEqual(element.getAttribute('href'), values[idx++], '<link rel="' + rel + '" ... /> has not been rendered correctly'); | ||
} | ||
} catch (err) { | ||
_didIteratorError = true; | ||
_iteratorError = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion && _iterator.return) { | ||
_iterator.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError) { | ||
throw _iteratorError; | ||
} | ||
} | ||
} | ||
}); | ||
}); | ||
describe('Deep nesting', function () { | ||
beforeEach(function () { | ||
_2.default.canUseDOM = true; | ||
(0, _dom.removeDocumentMeta)(); | ||
_reactAddonsTestUtils2.default.renderIntoDocument(_react2.default.createElement( | ||
_2.default, | ||
{ meta: { name: { l1: 'a' } } }, | ||
_react2.default.createElement( | ||
_2.default, | ||
{ meta: { name: { l2: 'b' } }, extend: true }, | ||
_react2.default.createElement( | ||
_2.default, | ||
{ meta: { name: { l3: 'c' } } }, | ||
_react2.default.createElement(_2.default, { meta: { name: { l4: 'd' } }, extend: true }) | ||
) | ||
) | ||
)); | ||
}); | ||
it('should render inside-out, but only as long as the parent component is extendable', function () { | ||
var expected = { l4: 'd', 'l3': 'c' }; | ||
var actual = {}; | ||
var elements = (0, _testUtils.getElements)('meta[name]'); | ||
var _iteratorNormalCompletion2 = true; | ||
var _didIteratorError2 = false; | ||
var _iteratorError2 = undefined; | ||
try { | ||
for (var _iterator2 = elements[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { | ||
var element = _step2.value; | ||
var name = element.getAttribute('name'); | ||
actual[name] = element.getAttribute('content'); | ||
} | ||
} catch (err) { | ||
_didIteratorError2 = true; | ||
_iteratorError2 = err; | ||
} finally { | ||
try { | ||
if (!_iteratorNormalCompletion2 && _iterator2.return) { | ||
_iterator2.return(); | ||
} | ||
} finally { | ||
if (_didIteratorError2) { | ||
throw _iteratorError2; | ||
} | ||
} | ||
} | ||
_assert2.default.deepEqual(expected, actual, '<meta name="..." content="..." /> has not been rendered correctly'); | ||
}); | ||
}); | ||
}); |
@@ -7,5 +7,7 @@ 'use strict'; | ||
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
@@ -18,4 +20,2 @@ var _react = require('react'); | ||
var _exenv = require('exenv'); | ||
var _reactSideEffect = require('react-side-effect'); | ||
@@ -27,4 +27,12 @@ | ||
var _dom = require('./dom'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } | ||
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
@@ -40,2 +48,4 @@ | ||
for (var i = propsList.length - 1; extend && i >= 0; i--) { | ||
extend = propsList[i].hasOwnProperty('extend'); | ||
var _props = (0, _utils.clone)(propsList[i]); | ||
@@ -51,7 +61,9 @@ | ||
(0, _utils.defaults)(props, _props); | ||
extend = _props.hasOwnProperty('extend'); | ||
} | ||
// Auto props | ||
if (props.auto) { | ||
autoProps(props); | ||
if (props.auto.ograph) { | ||
ograph(props); | ||
} | ||
} | ||
@@ -62,14 +74,6 @@ | ||
function autoProps(props) { | ||
if (props.auto.ograph === true) { | ||
ograph(props); | ||
} | ||
return props; | ||
} | ||
function handleStateChangeOnClient(props) { | ||
if (_exenv.canUseDOM) { | ||
if (_dom.canUseDOM) { | ||
document.title = props.title || ''; | ||
insertDocumentMeta(props); | ||
(0, _dom.insertDocumentMeta)(getTags(props)); | ||
} | ||
@@ -102,3 +106,3 @@ } | ||
function parseTags(tagName) { | ||
var props = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; | ||
var props = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
@@ -118,10 +122,9 @@ var tags = []; | ||
values.forEach(function (value) { | ||
var _tags$push2; | ||
if (value !== null) { | ||
var _tags$push2; | ||
if (value === null) { | ||
return; | ||
tags.push((_tags$push2 = { | ||
tagName: tagName | ||
}, _defineProperty(_tags$push2, groupKey, key), _defineProperty(_tags$push2, contentKey, value), _tags$push2)); | ||
} | ||
tags.push((_tags$push2 = { | ||
tagName: tagName | ||
}, _defineProperty(_tags$push2, groupKey, key), _defineProperty(_tags$push2, contentKey, value), _tags$push2)); | ||
}); | ||
@@ -137,33 +140,4 @@ }); | ||
function removeNode(node) { | ||
node.parentNode.removeChild(node); | ||
} | ||
function removeDocumentMeta() { | ||
(0, _utils.forEach)(document.querySelectorAll('head [data-rdm]'), removeNode); | ||
} | ||
function insertDocumentMetaNode(entry) { | ||
var tagName = entry.tagName; | ||
var attr = _objectWithoutProperties(entry, ['tagName']); | ||
var newNode = document.createElement(tagName); | ||
for (var prop in attr) { | ||
if (entry.hasOwnProperty(prop)) { | ||
newNode.setAttribute(prop, entry[prop]); | ||
} | ||
} | ||
newNode.setAttribute('data-rdm', ''); | ||
document.getElementsByTagName('head')[0].appendChild(newNode); | ||
} | ||
function insertDocumentMeta(props) { | ||
removeDocumentMeta(); | ||
(0, _utils.forEach)(getTags(props), insertDocumentMetaNode); | ||
} | ||
function render() { | ||
var meta = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0]; | ||
var meta = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; | ||
var opts = arguments[1]; | ||
@@ -174,2 +148,3 @@ | ||
} | ||
var i = 0; | ||
@@ -179,6 +154,5 @@ var tags = []; | ||
function renderTag(entry) { | ||
var tagName = entry.tagName; | ||
var tagName = entry.tagName, | ||
attr = _objectWithoutProperties(entry, ['tagName']); | ||
var attr = _objectWithoutProperties(entry, ['tagName']); | ||
if (tagName === 'meta') { | ||
@@ -214,29 +188,42 @@ return _react2.default.createElement('meta', _extends({}, attr, { key: i++, 'data-rdm': true })); | ||
tags | ||
)).replace(/(^<div>|<\/div>$)/g, ''); | ||
)).replace(/(^<div>|<\/div>$)/g, '').replace(/data-rdm="true"/g, 'data-rdm'); | ||
} | ||
var DocumentMeta = _react2.default.createClass({ | ||
displayName: 'DocumentMeta', | ||
var DocumentMeta = function (_Component) { | ||
_inherits(DocumentMeta, _Component); | ||
propTypes: { | ||
title: _react2.default.PropTypes.string, | ||
description: _react2.default.PropTypes.string, | ||
canonical: _react2.default.PropTypes.string, | ||
meta: _react2.default.PropTypes.objectOf(_react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.objectOf(_react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.arrayOf(_react2.default.PropTypes.string)]))])), | ||
link: _react2.default.PropTypes.objectOf(_react2.default.PropTypes.objectOf(_react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.arrayOf(_react2.default.PropTypes.string)]))), | ||
auto: _react2.default.PropTypes.objectOf(_react2.default.PropTypes.bool) | ||
}, | ||
function DocumentMeta() { | ||
_classCallCheck(this, DocumentMeta); | ||
render: function render() { | ||
var children = this.props.children; | ||
var count = _react2.default.Children.count(children); | ||
return count === 1 ? _react2.default.Children.only(children) : count ? _react2.default.createElement( | ||
'div', | ||
null, | ||
this.props.children | ||
) : null; | ||
return _possibleConstructorReturn(this, (DocumentMeta.__proto__ || Object.getPrototypeOf(DocumentMeta)).apply(this, arguments)); | ||
} | ||
}); | ||
_createClass(DocumentMeta, [{ | ||
key: 'render', | ||
value: function render() { | ||
var children = this.props.children; | ||
var count = _react2.default.Children.count(children); | ||
return count === 1 ? _react2.default.Children.only(children) : count ? _react2.default.createElement( | ||
'div', | ||
null, | ||
this.props.children | ||
) : null; | ||
} | ||
}]); | ||
return DocumentMeta; | ||
}(_react.Component); | ||
DocumentMeta.propTypes = { | ||
title: _react.PropTypes.string, | ||
description: _react.PropTypes.string, | ||
base: _react.PropTypes.string, | ||
canonical: _react.PropTypes.string, | ||
meta: _react.PropTypes.objectOf(_react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.objectOf(_react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.arrayOf(_react.PropTypes.string)]))])), | ||
link: _react.PropTypes.objectOf(_react.PropTypes.objectOf(_react.PropTypes.oneOfType([_react.PropTypes.string, _react.PropTypes.arrayOf(_react.PropTypes.string)]))), | ||
auto: _react.PropTypes.objectOf(_react.PropTypes.bool) | ||
}; | ||
var DocumentMetaWithSideEffect = (0, _reactSideEffect2.default)(reducePropsTostate, handleStateChangeOnClient)(DocumentMeta); | ||
@@ -252,2 +239,7 @@ | ||
DocumentMetaWithSideEffect.renderToStaticMarkup = function rewindAsHTML() { | ||
return render(DocumentMetaWithSideEffect.rewind(), { asHtml: true }); | ||
}; | ||
exports.default = DocumentMetaWithSideEffect; | ||
module.exports = exports['default']; |
@@ -7,3 +7,3 @@ 'use strict'; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; | ||
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
@@ -13,16 +13,16 @@ exports.clone = clone; | ||
exports.forEach = forEach; | ||
exports.removeDocumentMeta = removeDocumentMeta; | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
/** | ||
* Tools | ||
*/ | ||
function clone(_ref) { | ||
var children = _ref.children; | ||
var title = _ref.title, | ||
description = _ref.description, | ||
base = _ref.base, | ||
canonical = _ref.canonical, | ||
meta = _ref.meta, | ||
link = _ref.link, | ||
auto = _ref.auto; | ||
var source = _objectWithoutProperties(_ref, ['children']); | ||
return source ? JSON.parse(JSON.stringify(source)) : {}; | ||
try { | ||
return JSON.parse(JSON.stringify({ title: title, description: description, base: base, canonical: canonical, meta: meta, link: link, auto: auto })); | ||
} catch (x) { | ||
return {}; | ||
} | ||
} | ||
@@ -45,23 +45,1 @@ | ||
} | ||
/** | ||
* Validation | ||
*/ | ||
// const VALID_PROPS = ['title', 'description', 'canonical', 'meta', 'link']; | ||
// export function isValidProp ( propKey ) { | ||
// return ~VALID_PROPS.indexOf( propKey ); | ||
// } | ||
/** | ||
* Document manipulation | ||
*/ | ||
function removeNode(node) { | ||
node.parentNode.removeChild(node); | ||
} | ||
function removeDocumentMeta() { | ||
forEach(document.querySelectorAll('head [data-rdm]'), removeNode); | ||
} |
@@ -5,3 +5,3 @@ import assert from 'assert'; | ||
import DocumentMeta from '../'; | ||
import { removeDocumentMeta } from '../utils'; | ||
import { removeDocumentMeta } from '../dom'; | ||
import { getElements, getAttr } from './test-utils'; | ||
@@ -56,3 +56,3 @@ | ||
it('should render normal meta tags, eg. <meta name="..." content="...">', () => { | ||
Object.keys( DOC_META.meta.name ).reduce(( name ) => { | ||
Object.keys( DOC_META.meta.name ).forEach(name => { | ||
assert.strictEqual( getAttr(`meta[name=${ name }]`, 'content'), DOC_META.meta.name[name], `<meta name="${ name }" ... /> has not been rendered correctly` ); | ||
@@ -63,10 +63,11 @@ }); | ||
it('should render normal link tags, eg. <link rel="..." href="...">', () => { | ||
Object.keys( DOC_META.link.rel ).reduce(( rel ) => { | ||
Object.keys( DOC_META.link.rel ).forEach(rel => { | ||
const values = Array.isArray(DOC_META.link.rel[rel]) ? DOC_META.link.rel[rel] : [ DOC_META.link.rel[rel] ]; | ||
let idx = 0; | ||
const elements = getElements( `link[rel=${ rel }]` ); | ||
elements.forEach(( element, idx ) => { | ||
assert.strictEqual( element.getAttribute('content'), values[idx], `<link rel="${ rel }" ... /> has not been rendered correctly` ); | ||
}); | ||
for (const element of elements) { | ||
assert.strictEqual( element.getAttribute('href'), values[idx++], `<link rel="${ rel }" ... /> has not been rendered correctly` ); | ||
} | ||
}); | ||
}); | ||
}); | ||
}); |
@@ -5,3 +5,3 @@ import assert from 'assert'; | ||
import DocumentMeta from '../'; | ||
import { removeDocumentMeta } from '../utils'; | ||
import { removeDocumentMeta } from '../dom'; | ||
import { getElements, getAttr } from './test-utils'; | ||
@@ -61,11 +61,11 @@ | ||
it('should render document.title / <title> according to the title-attr', () => { | ||
it('should render document.title / <title> according to the nested title-prop', () => { | ||
assert.strictEqual( document.title, DOC_META_NESTED.title ); | ||
}); | ||
it('should render <meta name="description" content="..."> according to the description-attr', () => { | ||
it('should render <meta name="description" content="..."> according to the nested description-prop', () => { | ||
assert.strictEqual( getAttr('meta[name=description]', 'content'), DOC_META_NESTED.description ); | ||
}); | ||
it('should render <link rel="canonical" href="..." according to the canonical-attr', () => { | ||
it('should render <link rel="canonical" href="..." according to the nested canonical-prop', () => { | ||
assert.strictEqual( getAttr('link[rel=canonical]', 'href'), DOC_META_NESTED.canonical ); | ||
@@ -79,3 +79,3 @@ }); | ||
it('should render normal meta tags, eg. <meta name="..." content="...">', () => { | ||
Object.keys( DOC_META.meta.name ).reduce(( name ) => { | ||
Object.keys( DOC_META.meta.name ).forEach(name => { | ||
const value = DOC_META_NESTED.meta.name.hasOwnProperty(name) | ||
@@ -89,3 +89,3 @@ ? DOC_META_NESTED.meta.name[name] | ||
it('should render normal link tags, eg. <link rel="..." href="...">', () => { | ||
Object.keys( DOC_META.link.rel ).reduce(( rel ) => { | ||
Object.keys( DOC_META.link.rel ).forEach(rel => { | ||
const value = DOC_META_NESTED.link.rel.hasOwnProperty(rel) | ||
@@ -95,8 +95,39 @@ ? DOC_META_NESTED.link.rel[rel] | ||
const values = Array.isArray(value) ? value : [ value ]; | ||
let idx = 0; | ||
const elements = getElements( `link[rel=${ rel }]` ); | ||
elements.forEach(( element, idx ) => { | ||
assert.strictEqual( element.getAttribute('content'), values[idx], `<link rel="${ rel }" ... /> has not been rendered correctly` ); | ||
}); | ||
for (const element of elements) { | ||
assert.strictEqual( element.getAttribute('href'), values[idx++], `<link rel="${ rel }" ... /> has not been rendered correctly` ); | ||
} | ||
}); | ||
}); | ||
}); | ||
describe('Deep nesting', () => { | ||
beforeEach(() => { | ||
DocumentMeta.canUseDOM = true; | ||
removeDocumentMeta(); | ||
TestUtils.renderIntoDocument( | ||
<DocumentMeta meta={{ name: { l1: 'a' } }}> | ||
<DocumentMeta meta={{ name: { l2: 'b' } }} extend> | ||
<DocumentMeta meta={{ name: { l3: 'c' } }}> | ||
<DocumentMeta meta={{ name: { l4: 'd' } }} extend /> | ||
</DocumentMeta> | ||
</DocumentMeta> | ||
</DocumentMeta> | ||
); | ||
}); | ||
it('should render inside-out, but only as long as the parent component is extendable', () => { | ||
const expected = { l4: 'd', 'l3': 'c' }; | ||
const actual = {}; | ||
const elements = getElements(`meta[name]`); | ||
for (const element of elements) { | ||
const name = element.getAttribute('name'); | ||
actual[name] = element.getAttribute('content'); | ||
} | ||
assert.deepEqual(expected, actual, `<meta name="..." content="..." /> has not been rendered correctly`); | ||
}); | ||
}); | ||
}); |
134
lib/index.js
@@ -1,4 +0,3 @@ | ||
import React from 'react'; | ||
import React, { Component, PropTypes } from 'react'; | ||
import { renderToStaticMarkup } from 'react-dom/server'; | ||
import { canUseDOM } from 'exenv'; | ||
import withSideEffect from 'react-side-effect'; | ||
@@ -12,2 +11,8 @@ | ||
import { | ||
canUseDOM, | ||
removeDocumentMeta, | ||
insertDocumentMeta | ||
} from './dom'; | ||
function reducePropsTostate ( propsList ) { | ||
@@ -19,2 +24,4 @@ const props = {}; | ||
for (var i = propsList.length - 1; extend && i >= 0; i--) { | ||
extend = propsList[i].hasOwnProperty('extend'); | ||
const _props = clone(propsList[i]); | ||
@@ -30,7 +37,9 @@ | ||
defaults(props, _props); | ||
extend = _props.hasOwnProperty('extend'); | ||
} | ||
// Auto props | ||
if (props.auto) { | ||
autoProps( props ); | ||
if (props.auto.ograph) { | ||
ograph(props); | ||
} | ||
} | ||
@@ -41,14 +50,6 @@ | ||
function autoProps ( props ) { | ||
if (props.auto.ograph === true) { | ||
ograph(props); | ||
} | ||
return props; | ||
} | ||
function handleStateChangeOnClient ( props ) { | ||
if ( canUseDOM ) { | ||
function handleStateChangeOnClient(props) { | ||
if (canUseDOM) { | ||
document.title = props.title || ''; | ||
insertDocumentMeta( props ); | ||
insertDocumentMeta(getTags(props)); | ||
} | ||
@@ -80,6 +81,6 @@ } | ||
function parseTags ( tagName, props = {} ) { | ||
function parseTags (tagName, props = {}) { | ||
const tags = []; | ||
const contentKey = tagName === 'link' ? 'href' : 'content'; | ||
Object.keys( props ).forEach(( groupKey ) => { | ||
Object.keys(props).forEach(groupKey => { | ||
const group = props[groupKey]; | ||
@@ -93,13 +94,12 @@ if (typeof group === 'string') { | ||
} | ||
Object.keys( group ).forEach(( key ) => { | ||
Object.keys(group).forEach(key => { | ||
const values = Array.isArray(group[key]) ? group[key] : [group[key]]; | ||
values.forEach(( value ) => { | ||
if (value === null ) { | ||
return; | ||
values.forEach(value => { | ||
if (value !== null) { | ||
tags.push({ | ||
tagName, | ||
[ groupKey ]: key, | ||
[ contentKey ]: value | ||
}); | ||
} | ||
tags.push({ | ||
tagName, | ||
[ groupKey ]: key, | ||
[ contentKey ]: value | ||
}); | ||
}); | ||
@@ -115,30 +115,2 @@ }); | ||
function removeNode ( node ) { | ||
node.parentNode.removeChild(node); | ||
} | ||
function removeDocumentMeta () { | ||
forEach(document.querySelectorAll('head [data-rdm]'), removeNode); | ||
} | ||
function insertDocumentMetaNode ( entry ) { | ||
const { tagName, ...attr } = entry; | ||
var newNode = document.createElement( tagName ); | ||
for (var prop in attr) { | ||
if (entry.hasOwnProperty(prop)) { | ||
newNode.setAttribute(prop, entry[prop]); | ||
} | ||
} | ||
newNode.setAttribute('data-rdm', ''); | ||
document.getElementsByTagName('head')[0].appendChild(newNode); | ||
} | ||
function insertDocumentMeta ( props ) { | ||
removeDocumentMeta(); | ||
forEach( getTags( props ), insertDocumentMetaNode); | ||
} | ||
function render ( meta = {}, opts ) { | ||
@@ -148,6 +120,7 @@ if ( typeof opts !== 'object' ) { | ||
} | ||
let i = 0; | ||
const tags = []; | ||
function renderTag ( entry ) { | ||
function renderTag ( entry ) { | ||
const { tagName, ...attr } = entry; | ||
@@ -177,19 +150,18 @@ | ||
return renderToStaticMarkup( <div>{ tags }</div> ).replace(/(^<div>|<\/div>$)/g, ''); | ||
return renderToStaticMarkup( <div>{ tags }</div> ).replace(/(^<div>|<\/div>$)/g, '').replace(/data-rdm="true"/g, 'data-rdm'); | ||
} | ||
const DocumentMeta = React.createClass({ | ||
displayName: 'DocumentMeta', | ||
propTypes: { | ||
title: React.PropTypes.string, | ||
description: React.PropTypes.string, | ||
canonical: React.PropTypes.string, | ||
meta: React.PropTypes.objectOf( | ||
React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.objectOf( | ||
React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.arrayOf(React.PropTypes.string) | ||
class DocumentMeta extends Component { | ||
static propTypes = { | ||
title: PropTypes.string, | ||
description: PropTypes.string, | ||
base: PropTypes.string, | ||
canonical: PropTypes.string, | ||
meta: PropTypes.objectOf( | ||
PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.objectOf( | ||
PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.arrayOf(PropTypes.string) | ||
]) | ||
@@ -199,14 +171,14 @@ ) | ||
), | ||
link: React.PropTypes.objectOf( | ||
React.PropTypes.objectOf( | ||
React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.arrayOf(React.PropTypes.string) | ||
link: PropTypes.objectOf( | ||
PropTypes.objectOf( | ||
PropTypes.oneOfType([ | ||
PropTypes.string, | ||
PropTypes.arrayOf(PropTypes.string) | ||
]) | ||
) | ||
), | ||
auto: React.PropTypes.objectOf(React.PropTypes.bool) | ||
}, | ||
auto: PropTypes.objectOf(PropTypes.bool) | ||
} | ||
render: function render () { | ||
render() { | ||
const { children } = this.props; | ||
@@ -216,3 +188,3 @@ const count = React.Children.count(children); | ||
} | ||
}); | ||
} | ||
@@ -232,2 +204,6 @@ const DocumentMetaWithSideEffect = withSideEffect( | ||
DocumentMetaWithSideEffect.renderToStaticMarkup = function rewindAsHTML () { | ||
return render( DocumentMetaWithSideEffect.rewind(), { asHtml: true } ); | ||
}; | ||
export default DocumentMetaWithSideEffect; |
@@ -1,7 +0,8 @@ | ||
/** | ||
* Tools | ||
*/ | ||
export function clone ({ children, ...source }) { | ||
return source ? JSON.parse( JSON.stringify( source ) ) : {}; | ||
export function clone ({ title, description, base, canonical, meta, link, auto }) { | ||
try { | ||
return JSON.parse(JSON.stringify({ title, description, base, canonical, meta, link, auto })); | ||
} | ||
catch(x) { | ||
return {}; | ||
} | ||
} | ||
@@ -25,23 +26,1 @@ | ||
} | ||
/** | ||
* Validation | ||
*/ | ||
// const VALID_PROPS = ['title', 'description', 'canonical', 'meta', 'link']; | ||
// export function isValidProp ( propKey ) { | ||
// return ~VALID_PROPS.indexOf( propKey ); | ||
// } | ||
/** | ||
* Document manipulation | ||
*/ | ||
function removeNode ( node ) { | ||
node.parentNode.removeChild(node); | ||
} | ||
export function removeDocumentMeta () { | ||
forEach(document.querySelectorAll('head [data-rdm]'), removeNode); | ||
} |
{ | ||
"name": "react-document-meta", | ||
"version": "2.0.3", | ||
"version": "2.1.0", | ||
"description": "Declarative, nested and stateful HTML document meta tags for React", | ||
@@ -18,26 +18,26 @@ "main": "./dist/index", | ||
"devDependencies": { | ||
"babel": "^6.3.26", | ||
"babel-cli": "^6.3.17", | ||
"babel-core": "^6.3.26", | ||
"babel-eslint": "^5.0.0", | ||
"babel-istanbul": "^0.6.0", | ||
"babel-loader": "^6.2.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.3.13", | ||
"babel-preset-es2015": "^6.3.13", | ||
"babel-preset-react": "^6.3.13", | ||
"babel-register": "^6.3.13", | ||
"coveralls": "^2.11.6", | ||
"eslint": "^1.3.1", | ||
"eslint-plugin-react": "^3.3.1", | ||
"express": "^4.13.3", | ||
"jsdom": "^7.0.1", | ||
"mocha": "^2.3.0", | ||
"react": "^15.0.0", | ||
"react-addons-test-utils": "^15.0.0", | ||
"babel-cli": "^6.18.0", | ||
"babel-core": "^6.18.2", | ||
"babel-eslint": "^7.1.1", | ||
"babel-istanbul": "^0.11.0", | ||
"babel-loader": "^6.2.8", | ||
"babel-plugin-add-module-exports": "^0.2.1", | ||
"babel-plugin-transform-class-properties": "^6.19.0", | ||
"babel-plugin-transform-object-rest-spread": "^6.19.0", | ||
"babel-preset-es2015": "^6.18.0", | ||
"babel-preset-react": "^6.16.0", | ||
"babel-register": "^6.18.0", | ||
"coveralls": "^2.11.15", | ||
"eslint": "^3.10.2", | ||
"eslint-plugin-react": "^6.7.1", | ||
"express": "^4.14.0", | ||
"jsdom": "^9.8.3", | ||
"mocha": "^3.1.2", | ||
"react-addons-test-utils": "^15.4.1", | ||
"react-hot-loader": "^1.3.0", | ||
"webpack": "^1.12.1", | ||
"webpack-dev-server": "^1.10.1" | ||
"webpack": "^1.13.3", | ||
"webpack-dev-server": "^1.16.2" | ||
}, | ||
"dependencies": { | ||
"exenv": "^1.2.0", | ||
"react": ">=0.14.0", | ||
"react-dom": ">=0.14.0", | ||
@@ -44,0 +44,0 @@ "react-side-effect": "^1.0.1" |
@@ -1,2 +0,2 @@ | ||
React Document Meta [![Build Status](https://travis-ci.org/kodyl/react-document-meta.svg)](https://travis-ci.org/kodyl/react-document-meta) [![Coverage Status](https://coveralls.io/repos/kodyl/react-document-meta/badge.svg?branch=master&service=github)](https://coveralls.io/github/kodyl/react-document-meta?branch=master) [![npm version](https://badge.fury.io/js/react-document-meta.svg)](http://badge.fury.io/js/react-document-meta) | ||
React Document Meta [![Build Status](https://travis-ci.org/kodyl/react-document-meta.svg)](https://travis-ci.org/kodyl/react-document-meta) [![Coverage Status](https://coveralls.io/repos/github/kodyl/react-document-meta/badge.svg?branch=master)](https://coveralls.io/github/kodyl/react-document-meta?branch=master) [![npm version](https://badge.fury.io/js/react-document-meta.svg)](http://badge.fury.io/js/react-document-meta) | ||
=================== | ||
@@ -83,3 +83,27 @@ | ||
```javascript | ||
import React from 'react'; | ||
import DocumentMeta from 'react-document-meta'; | ||
export default handler = (...args) => { | ||
... | ||
const app = React.renderToString(components); | ||
const meta = DocumentMeta.renderAsHTML(); | ||
const markup = ` | ||
<html> | ||
<head> | ||
${meta} | ||
</head> | ||
<body> | ||
<div id="app"> | ||
${app} | ||
</div> | ||
</body> | ||
</html> | ||
` | ||
... | ||
} | ||
``` | ||
TODO: | ||
@@ -86,0 +110,0 @@ ------------------- |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
52558
26
1100
112
+ Addedreact@>=0.14.0
- Removedexenv@^1.2.0
- Removedexenv@1.2.2(transitive)