- Added primary_keyword, secondary_keywords, tags, and categories fields to Tasks model - Updated generate_content function to handle full JSON response with all SEO fields - Improved progress bar animation: smooth 1% increments every 300ms - Enhanced step detection for content generation vs clustering vs ideas - Fixed progress modal to show correct messages for each function type - Added comprehensive logging to Keywords and Tasks pages for AI functions - Fixed error handling to show meaningful error messages instead of generic failures
974 lines
32 KiB
JavaScript
974 lines
32 KiB
JavaScript
import {
|
|
require_react
|
|
} from "./chunk-S5FHZHKU.js";
|
|
import {
|
|
__commonJS,
|
|
__publicField,
|
|
__toESM
|
|
} from "./chunk-EQCVQC35.js";
|
|
|
|
// node_modules/react-fast-compare/index.js
|
|
var require_react_fast_compare = __commonJS({
|
|
"node_modules/react-fast-compare/index.js"(exports, module) {
|
|
var hasElementType = typeof Element !== "undefined";
|
|
var hasMap = typeof Map === "function";
|
|
var hasSet = typeof Set === "function";
|
|
var hasArrayBuffer = typeof ArrayBuffer === "function" && !!ArrayBuffer.isView;
|
|
function equal(a, b) {
|
|
if (a === b) return true;
|
|
if (a && b && typeof a == "object" && typeof b == "object") {
|
|
if (a.constructor !== b.constructor) return false;
|
|
var length, i, keys;
|
|
if (Array.isArray(a)) {
|
|
length = a.length;
|
|
if (length != b.length) return false;
|
|
for (i = length; i-- !== 0; )
|
|
if (!equal(a[i], b[i])) return false;
|
|
return true;
|
|
}
|
|
var it;
|
|
if (hasMap && a instanceof Map && b instanceof Map) {
|
|
if (a.size !== b.size) return false;
|
|
it = a.entries();
|
|
while (!(i = it.next()).done)
|
|
if (!b.has(i.value[0])) return false;
|
|
it = a.entries();
|
|
while (!(i = it.next()).done)
|
|
if (!equal(i.value[1], b.get(i.value[0]))) return false;
|
|
return true;
|
|
}
|
|
if (hasSet && a instanceof Set && b instanceof Set) {
|
|
if (a.size !== b.size) return false;
|
|
it = a.entries();
|
|
while (!(i = it.next()).done)
|
|
if (!b.has(i.value[0])) return false;
|
|
return true;
|
|
}
|
|
if (hasArrayBuffer && ArrayBuffer.isView(a) && ArrayBuffer.isView(b)) {
|
|
length = a.length;
|
|
if (length != b.length) return false;
|
|
for (i = length; i-- !== 0; )
|
|
if (a[i] !== b[i]) return false;
|
|
return true;
|
|
}
|
|
if (a.constructor === RegExp) return a.source === b.source && a.flags === b.flags;
|
|
if (a.valueOf !== Object.prototype.valueOf && typeof a.valueOf === "function" && typeof b.valueOf === "function") return a.valueOf() === b.valueOf();
|
|
if (a.toString !== Object.prototype.toString && typeof a.toString === "function" && typeof b.toString === "function") return a.toString() === b.toString();
|
|
keys = Object.keys(a);
|
|
length = keys.length;
|
|
if (length !== Object.keys(b).length) return false;
|
|
for (i = length; i-- !== 0; )
|
|
if (!Object.prototype.hasOwnProperty.call(b, keys[i])) return false;
|
|
if (hasElementType && a instanceof Element) return false;
|
|
for (i = length; i-- !== 0; ) {
|
|
if ((keys[i] === "_owner" || keys[i] === "__v" || keys[i] === "__o") && a.$$typeof) {
|
|
continue;
|
|
}
|
|
if (!equal(a[keys[i]], b[keys[i]])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
return a !== a && b !== b;
|
|
}
|
|
module.exports = function isEqual(a, b) {
|
|
try {
|
|
return equal(a, b);
|
|
} catch (error) {
|
|
if ((error.message || "").match(/stack|recursion/i)) {
|
|
console.warn("react-fast-compare cannot handle circular refs");
|
|
return false;
|
|
}
|
|
throw error;
|
|
}
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/invariant/browser.js
|
|
var require_browser = __commonJS({
|
|
"node_modules/invariant/browser.js"(exports, module) {
|
|
"use strict";
|
|
var invariant2 = function(condition, format, a, b, c, d, e, f) {
|
|
if (true) {
|
|
if (format === void 0) {
|
|
throw new Error("invariant requires an error message argument");
|
|
}
|
|
}
|
|
if (!condition) {
|
|
var error;
|
|
if (format === void 0) {
|
|
error = new Error(
|
|
"Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings."
|
|
);
|
|
} else {
|
|
var args = [a, b, c, d, e, f];
|
|
var argIndex = 0;
|
|
error = new Error(
|
|
format.replace(/%s/g, function() {
|
|
return args[argIndex++];
|
|
})
|
|
);
|
|
error.name = "Invariant Violation";
|
|
}
|
|
error.framesToPop = 1;
|
|
throw error;
|
|
}
|
|
};
|
|
module.exports = invariant2;
|
|
}
|
|
});
|
|
|
|
// node_modules/shallowequal/index.js
|
|
var require_shallowequal = __commonJS({
|
|
"node_modules/shallowequal/index.js"(exports, module) {
|
|
module.exports = function shallowEqual2(objA, objB, compare, compareContext) {
|
|
var ret = compare ? compare.call(compareContext, objA, objB) : void 0;
|
|
if (ret !== void 0) {
|
|
return !!ret;
|
|
}
|
|
if (objA === objB) {
|
|
return true;
|
|
}
|
|
if (typeof objA !== "object" || !objA || typeof objB !== "object" || !objB) {
|
|
return false;
|
|
}
|
|
var keysA = Object.keys(objA);
|
|
var keysB = Object.keys(objB);
|
|
if (keysA.length !== keysB.length) {
|
|
return false;
|
|
}
|
|
var bHasOwnProperty = Object.prototype.hasOwnProperty.bind(objB);
|
|
for (var idx = 0; idx < keysA.length; idx++) {
|
|
var key = keysA[idx];
|
|
if (!bHasOwnProperty(key)) {
|
|
return false;
|
|
}
|
|
var valueA = objA[key];
|
|
var valueB = objB[key];
|
|
ret = compare ? compare.call(compareContext, valueA, valueB, key) : void 0;
|
|
if (ret === false || ret === void 0 && valueA !== valueB) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
};
|
|
}
|
|
});
|
|
|
|
// node_modules/react-helmet-async/lib/index.esm.js
|
|
var import_react = __toESM(require_react());
|
|
var import_react_fast_compare = __toESM(require_react_fast_compare());
|
|
var import_invariant = __toESM(require_browser());
|
|
var import_react2 = __toESM(require_react());
|
|
var import_react3 = __toESM(require_react());
|
|
var import_react4 = __toESM(require_react());
|
|
var import_shallowequal = __toESM(require_shallowequal());
|
|
var TAG_NAMES = ((TAG_NAMES2) => {
|
|
TAG_NAMES2["BASE"] = "base";
|
|
TAG_NAMES2["BODY"] = "body";
|
|
TAG_NAMES2["HEAD"] = "head";
|
|
TAG_NAMES2["HTML"] = "html";
|
|
TAG_NAMES2["LINK"] = "link";
|
|
TAG_NAMES2["META"] = "meta";
|
|
TAG_NAMES2["NOSCRIPT"] = "noscript";
|
|
TAG_NAMES2["SCRIPT"] = "script";
|
|
TAG_NAMES2["STYLE"] = "style";
|
|
TAG_NAMES2["TITLE"] = "title";
|
|
TAG_NAMES2["FRAGMENT"] = "Symbol(react.fragment)";
|
|
return TAG_NAMES2;
|
|
})(TAG_NAMES || {});
|
|
var SEO_PRIORITY_TAGS = {
|
|
link: { rel: ["amphtml", "canonical", "alternate"] },
|
|
script: { type: ["application/ld+json"] },
|
|
meta: {
|
|
charset: "",
|
|
name: ["generator", "robots", "description"],
|
|
property: [
|
|
"og:type",
|
|
"og:title",
|
|
"og:url",
|
|
"og:image",
|
|
"og:image:alt",
|
|
"og:description",
|
|
"twitter:url",
|
|
"twitter:title",
|
|
"twitter:description",
|
|
"twitter:image",
|
|
"twitter:image:alt",
|
|
"twitter:card",
|
|
"twitter:site"
|
|
]
|
|
}
|
|
};
|
|
var VALID_TAG_NAMES = Object.values(TAG_NAMES);
|
|
var REACT_TAG_MAP = {
|
|
accesskey: "accessKey",
|
|
charset: "charSet",
|
|
class: "className",
|
|
contenteditable: "contentEditable",
|
|
contextmenu: "contextMenu",
|
|
"http-equiv": "httpEquiv",
|
|
itemprop: "itemProp",
|
|
tabindex: "tabIndex"
|
|
};
|
|
var HTML_TAG_MAP = Object.entries(REACT_TAG_MAP).reduce(
|
|
(carry, [key, value]) => {
|
|
carry[value] = key;
|
|
return carry;
|
|
},
|
|
{}
|
|
);
|
|
var HELMET_ATTRIBUTE = "data-rh";
|
|
var HELMET_PROPS = {
|
|
DEFAULT_TITLE: "defaultTitle",
|
|
DEFER: "defer",
|
|
ENCODE_SPECIAL_CHARACTERS: "encodeSpecialCharacters",
|
|
ON_CHANGE_CLIENT_STATE: "onChangeClientState",
|
|
TITLE_TEMPLATE: "titleTemplate",
|
|
PRIORITIZE_SEO_TAGS: "prioritizeSeoTags"
|
|
};
|
|
var getInnermostProperty = (propsList, property) => {
|
|
for (let i = propsList.length - 1; i >= 0; i -= 1) {
|
|
const props = propsList[i];
|
|
if (Object.prototype.hasOwnProperty.call(props, property)) {
|
|
return props[property];
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
var getTitleFromPropsList = (propsList) => {
|
|
let innermostTitle = getInnermostProperty(
|
|
propsList,
|
|
"title"
|
|
/* TITLE */
|
|
);
|
|
const innermostTemplate = getInnermostProperty(propsList, HELMET_PROPS.TITLE_TEMPLATE);
|
|
if (Array.isArray(innermostTitle)) {
|
|
innermostTitle = innermostTitle.join("");
|
|
}
|
|
if (innermostTemplate && innermostTitle) {
|
|
return innermostTemplate.replace(/%s/g, () => innermostTitle);
|
|
}
|
|
const innermostDefaultTitle = getInnermostProperty(propsList, HELMET_PROPS.DEFAULT_TITLE);
|
|
return innermostTitle || innermostDefaultTitle || void 0;
|
|
};
|
|
var getOnChangeClientState = (propsList) => getInnermostProperty(propsList, HELMET_PROPS.ON_CHANGE_CLIENT_STATE) || (() => {
|
|
});
|
|
var getAttributesFromPropsList = (tagType, propsList) => propsList.filter((props) => typeof props[tagType] !== "undefined").map((props) => props[tagType]).reduce((tagAttrs, current) => ({ ...tagAttrs, ...current }), {});
|
|
var getBaseTagFromPropsList = (primaryAttributes, propsList) => propsList.filter((props) => typeof props[
|
|
"base"
|
|
/* BASE */
|
|
] !== "undefined").map((props) => props[
|
|
"base"
|
|
/* BASE */
|
|
]).reverse().reduce((innermostBaseTag, tag) => {
|
|
if (!innermostBaseTag.length) {
|
|
const keys = Object.keys(tag);
|
|
for (let i = 0; i < keys.length; i += 1) {
|
|
const attributeKey = keys[i];
|
|
const lowerCaseAttributeKey = attributeKey.toLowerCase();
|
|
if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && tag[lowerCaseAttributeKey]) {
|
|
return innermostBaseTag.concat(tag);
|
|
}
|
|
}
|
|
}
|
|
return innermostBaseTag;
|
|
}, []);
|
|
var warn = (msg) => console && typeof console.warn === "function" && console.warn(msg);
|
|
var getTagsFromPropsList = (tagName, primaryAttributes, propsList) => {
|
|
const approvedSeenTags = {};
|
|
return propsList.filter((props) => {
|
|
if (Array.isArray(props[tagName])) {
|
|
return true;
|
|
}
|
|
if (typeof props[tagName] !== "undefined") {
|
|
warn(
|
|
`Helmet: ${tagName} should be of type "Array". Instead found type "${typeof props[tagName]}"`
|
|
);
|
|
}
|
|
return false;
|
|
}).map((props) => props[tagName]).reverse().reduce((approvedTags, instanceTags) => {
|
|
const instanceSeenTags = {};
|
|
instanceTags.filter((tag) => {
|
|
let primaryAttributeKey;
|
|
const keys2 = Object.keys(tag);
|
|
for (let i = 0; i < keys2.length; i += 1) {
|
|
const attributeKey = keys2[i];
|
|
const lowerCaseAttributeKey = attributeKey.toLowerCase();
|
|
if (primaryAttributes.indexOf(lowerCaseAttributeKey) !== -1 && !(primaryAttributeKey === "rel" && tag[primaryAttributeKey].toLowerCase() === "canonical") && !(lowerCaseAttributeKey === "rel" && tag[lowerCaseAttributeKey].toLowerCase() === "stylesheet")) {
|
|
primaryAttributeKey = lowerCaseAttributeKey;
|
|
}
|
|
if (primaryAttributes.indexOf(attributeKey) !== -1 && (attributeKey === "innerHTML" || attributeKey === "cssText" || attributeKey === "itemprop")) {
|
|
primaryAttributeKey = attributeKey;
|
|
}
|
|
}
|
|
if (!primaryAttributeKey || !tag[primaryAttributeKey]) {
|
|
return false;
|
|
}
|
|
const value = tag[primaryAttributeKey].toLowerCase();
|
|
if (!approvedSeenTags[primaryAttributeKey]) {
|
|
approvedSeenTags[primaryAttributeKey] = {};
|
|
}
|
|
if (!instanceSeenTags[primaryAttributeKey]) {
|
|
instanceSeenTags[primaryAttributeKey] = {};
|
|
}
|
|
if (!approvedSeenTags[primaryAttributeKey][value]) {
|
|
instanceSeenTags[primaryAttributeKey][value] = true;
|
|
return true;
|
|
}
|
|
return false;
|
|
}).reverse().forEach((tag) => approvedTags.push(tag));
|
|
const keys = Object.keys(instanceSeenTags);
|
|
for (let i = 0; i < keys.length; i += 1) {
|
|
const attributeKey = keys[i];
|
|
const tagUnion = {
|
|
...approvedSeenTags[attributeKey],
|
|
...instanceSeenTags[attributeKey]
|
|
};
|
|
approvedSeenTags[attributeKey] = tagUnion;
|
|
}
|
|
return approvedTags;
|
|
}, []).reverse();
|
|
};
|
|
var getAnyTrueFromPropsList = (propsList, checkedTag) => {
|
|
if (Array.isArray(propsList) && propsList.length) {
|
|
for (let index = 0; index < propsList.length; index += 1) {
|
|
const prop = propsList[index];
|
|
if (prop[checkedTag]) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var reducePropsToState = (propsList) => ({
|
|
baseTag: getBaseTagFromPropsList([
|
|
"href"
|
|
/* HREF */
|
|
], propsList),
|
|
bodyAttributes: getAttributesFromPropsList("bodyAttributes", propsList),
|
|
defer: getInnermostProperty(propsList, HELMET_PROPS.DEFER),
|
|
encode: getInnermostProperty(propsList, HELMET_PROPS.ENCODE_SPECIAL_CHARACTERS),
|
|
htmlAttributes: getAttributesFromPropsList("htmlAttributes", propsList),
|
|
linkTags: getTagsFromPropsList(
|
|
"link",
|
|
[
|
|
"rel",
|
|
"href"
|
|
/* HREF */
|
|
],
|
|
propsList
|
|
),
|
|
metaTags: getTagsFromPropsList(
|
|
"meta",
|
|
[
|
|
"name",
|
|
"charset",
|
|
"http-equiv",
|
|
"property",
|
|
"itemprop"
|
|
/* ITEM_PROP */
|
|
],
|
|
propsList
|
|
),
|
|
noscriptTags: getTagsFromPropsList("noscript", [
|
|
"innerHTML"
|
|
/* INNER_HTML */
|
|
], propsList),
|
|
onChangeClientState: getOnChangeClientState(propsList),
|
|
scriptTags: getTagsFromPropsList(
|
|
"script",
|
|
[
|
|
"src",
|
|
"innerHTML"
|
|
/* INNER_HTML */
|
|
],
|
|
propsList
|
|
),
|
|
styleTags: getTagsFromPropsList("style", [
|
|
"cssText"
|
|
/* CSS_TEXT */
|
|
], propsList),
|
|
title: getTitleFromPropsList(propsList),
|
|
titleAttributes: getAttributesFromPropsList("titleAttributes", propsList),
|
|
prioritizeSeoTags: getAnyTrueFromPropsList(propsList, HELMET_PROPS.PRIORITIZE_SEO_TAGS)
|
|
});
|
|
var flattenArray = (possibleArray) => Array.isArray(possibleArray) ? possibleArray.join("") : possibleArray;
|
|
var checkIfPropsMatch = (props, toMatch) => {
|
|
const keys = Object.keys(props);
|
|
for (let i = 0; i < keys.length; i += 1) {
|
|
if (toMatch[keys[i]] && toMatch[keys[i]].includes(props[keys[i]])) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
};
|
|
var prioritizer = (elementsList, propsToMatch) => {
|
|
if (Array.isArray(elementsList)) {
|
|
return elementsList.reduce(
|
|
(acc, elementAttrs) => {
|
|
if (checkIfPropsMatch(elementAttrs, propsToMatch)) {
|
|
acc.priority.push(elementAttrs);
|
|
} else {
|
|
acc.default.push(elementAttrs);
|
|
}
|
|
return acc;
|
|
},
|
|
{ priority: [], default: [] }
|
|
);
|
|
}
|
|
return { default: elementsList, priority: [] };
|
|
};
|
|
var without = (obj, key) => {
|
|
return {
|
|
...obj,
|
|
[key]: void 0
|
|
};
|
|
};
|
|
var SELF_CLOSING_TAGS = [
|
|
"noscript",
|
|
"script",
|
|
"style"
|
|
/* STYLE */
|
|
];
|
|
var encodeSpecialCharacters = (str, encode = true) => {
|
|
if (encode === false) {
|
|
return String(str);
|
|
}
|
|
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
};
|
|
var generateElementAttributesAsString = (attributes) => Object.keys(attributes).reduce((str, key) => {
|
|
const attr = typeof attributes[key] !== "undefined" ? `${key}="${attributes[key]}"` : `${key}`;
|
|
return str ? `${str} ${attr}` : attr;
|
|
}, "");
|
|
var generateTitleAsString = (type, title, attributes, encode) => {
|
|
const attributeString = generateElementAttributesAsString(attributes);
|
|
const flattenedTitle = flattenArray(title);
|
|
return attributeString ? `<${type} ${HELMET_ATTRIBUTE}="true" ${attributeString}>${encodeSpecialCharacters(
|
|
flattenedTitle,
|
|
encode
|
|
)}</${type}>` : `<${type} ${HELMET_ATTRIBUTE}="true">${encodeSpecialCharacters(
|
|
flattenedTitle,
|
|
encode
|
|
)}</${type}>`;
|
|
};
|
|
var generateTagsAsString = (type, tags, encode = true) => tags.reduce((str, t) => {
|
|
const tag = t;
|
|
const attributeHtml = Object.keys(tag).filter(
|
|
(attribute) => !(attribute === "innerHTML" || attribute === "cssText")
|
|
).reduce((string, attribute) => {
|
|
const attr = typeof tag[attribute] === "undefined" ? attribute : `${attribute}="${encodeSpecialCharacters(tag[attribute], encode)}"`;
|
|
return string ? `${string} ${attr}` : attr;
|
|
}, "");
|
|
const tagContent = tag.innerHTML || tag.cssText || "";
|
|
const isSelfClosing = SELF_CLOSING_TAGS.indexOf(type) === -1;
|
|
return `${str}<${type} ${HELMET_ATTRIBUTE}="true" ${attributeHtml}${isSelfClosing ? `/>` : `>${tagContent}</${type}>`}`;
|
|
}, "");
|
|
var convertElementAttributesToReactProps = (attributes, initProps = {}) => Object.keys(attributes).reduce((obj, key) => {
|
|
const mapped = REACT_TAG_MAP[key];
|
|
obj[mapped || key] = attributes[key];
|
|
return obj;
|
|
}, initProps);
|
|
var generateTitleAsReactComponent = (_type, title, attributes) => {
|
|
const initProps = {
|
|
key: title,
|
|
[HELMET_ATTRIBUTE]: true
|
|
};
|
|
const props = convertElementAttributesToReactProps(attributes, initProps);
|
|
return [import_react3.default.createElement("title", props, title)];
|
|
};
|
|
var generateTagsAsReactComponent = (type, tags) => tags.map((tag, i) => {
|
|
const mappedTag = {
|
|
key: i,
|
|
[HELMET_ATTRIBUTE]: true
|
|
};
|
|
Object.keys(tag).forEach((attribute) => {
|
|
const mapped = REACT_TAG_MAP[attribute];
|
|
const mappedAttribute = mapped || attribute;
|
|
if (mappedAttribute === "innerHTML" || mappedAttribute === "cssText") {
|
|
const content = tag.innerHTML || tag.cssText;
|
|
mappedTag.dangerouslySetInnerHTML = { __html: content };
|
|
} else {
|
|
mappedTag[mappedAttribute] = tag[attribute];
|
|
}
|
|
});
|
|
return import_react3.default.createElement(type, mappedTag);
|
|
});
|
|
var getMethodsForTag = (type, tags, encode = true) => {
|
|
switch (type) {
|
|
case "title":
|
|
return {
|
|
toComponent: () => generateTitleAsReactComponent(type, tags.title, tags.titleAttributes),
|
|
toString: () => generateTitleAsString(type, tags.title, tags.titleAttributes, encode)
|
|
};
|
|
case "bodyAttributes":
|
|
case "htmlAttributes":
|
|
return {
|
|
toComponent: () => convertElementAttributesToReactProps(tags),
|
|
toString: () => generateElementAttributesAsString(tags)
|
|
};
|
|
default:
|
|
return {
|
|
toComponent: () => generateTagsAsReactComponent(type, tags),
|
|
toString: () => generateTagsAsString(type, tags, encode)
|
|
};
|
|
}
|
|
};
|
|
var getPriorityMethods = ({ metaTags, linkTags, scriptTags, encode }) => {
|
|
const meta = prioritizer(metaTags, SEO_PRIORITY_TAGS.meta);
|
|
const link = prioritizer(linkTags, SEO_PRIORITY_TAGS.link);
|
|
const script = prioritizer(scriptTags, SEO_PRIORITY_TAGS.script);
|
|
const priorityMethods = {
|
|
toComponent: () => [
|
|
...generateTagsAsReactComponent("meta", meta.priority),
|
|
...generateTagsAsReactComponent("link", link.priority),
|
|
...generateTagsAsReactComponent("script", script.priority)
|
|
],
|
|
toString: () => (
|
|
// generate all the tags as strings and concatenate them
|
|
`${getMethodsForTag("meta", meta.priority, encode)} ${getMethodsForTag(
|
|
"link",
|
|
link.priority,
|
|
encode
|
|
)} ${getMethodsForTag("script", script.priority, encode)}`
|
|
)
|
|
};
|
|
return {
|
|
priorityMethods,
|
|
metaTags: meta.default,
|
|
linkTags: link.default,
|
|
scriptTags: script.default
|
|
};
|
|
};
|
|
var mapStateOnServer = (props) => {
|
|
const {
|
|
baseTag,
|
|
bodyAttributes,
|
|
encode = true,
|
|
htmlAttributes,
|
|
noscriptTags,
|
|
styleTags,
|
|
title = "",
|
|
titleAttributes,
|
|
prioritizeSeoTags
|
|
} = props;
|
|
let { linkTags, metaTags, scriptTags } = props;
|
|
let priorityMethods = {
|
|
toComponent: () => {
|
|
},
|
|
toString: () => ""
|
|
};
|
|
if (prioritizeSeoTags) {
|
|
({ priorityMethods, linkTags, metaTags, scriptTags } = getPriorityMethods(props));
|
|
}
|
|
return {
|
|
priority: priorityMethods,
|
|
base: getMethodsForTag("base", baseTag, encode),
|
|
bodyAttributes: getMethodsForTag("bodyAttributes", bodyAttributes, encode),
|
|
htmlAttributes: getMethodsForTag("htmlAttributes", htmlAttributes, encode),
|
|
link: getMethodsForTag("link", linkTags, encode),
|
|
meta: getMethodsForTag("meta", metaTags, encode),
|
|
noscript: getMethodsForTag("noscript", noscriptTags, encode),
|
|
script: getMethodsForTag("script", scriptTags, encode),
|
|
style: getMethodsForTag("style", styleTags, encode),
|
|
title: getMethodsForTag("title", { title, titleAttributes }, encode)
|
|
};
|
|
};
|
|
var server_default = mapStateOnServer;
|
|
var instances = [];
|
|
var isDocument = !!(typeof window !== "undefined" && window.document && window.document.createElement);
|
|
var HelmetData = class {
|
|
constructor(context, canUseDOM) {
|
|
__publicField(this, "instances", []);
|
|
__publicField(this, "canUseDOM", isDocument);
|
|
__publicField(this, "context");
|
|
__publicField(this, "value", {
|
|
setHelmet: (serverState) => {
|
|
this.context.helmet = serverState;
|
|
},
|
|
helmetInstances: {
|
|
get: () => this.canUseDOM ? instances : this.instances,
|
|
add: (instance) => {
|
|
(this.canUseDOM ? instances : this.instances).push(instance);
|
|
},
|
|
remove: (instance) => {
|
|
const index = (this.canUseDOM ? instances : this.instances).indexOf(instance);
|
|
(this.canUseDOM ? instances : this.instances).splice(index, 1);
|
|
}
|
|
}
|
|
});
|
|
this.context = context;
|
|
this.canUseDOM = canUseDOM || false;
|
|
if (!canUseDOM) {
|
|
context.helmet = server_default({
|
|
baseTag: [],
|
|
bodyAttributes: {},
|
|
encodeSpecialCharacters: true,
|
|
htmlAttributes: {},
|
|
linkTags: [],
|
|
metaTags: [],
|
|
noscriptTags: [],
|
|
scriptTags: [],
|
|
styleTags: [],
|
|
title: "",
|
|
titleAttributes: {}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
var defaultValue = {};
|
|
var Context = import_react2.default.createContext(defaultValue);
|
|
var _a;
|
|
var HelmetProvider = (_a = class extends import_react2.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
__publicField(this, "helmetData");
|
|
this.helmetData = new HelmetData(this.props.context || {}, _a.canUseDOM);
|
|
}
|
|
render() {
|
|
return import_react2.default.createElement(Context.Provider, { value: this.helmetData.value }, this.props.children);
|
|
}
|
|
}, __publicField(_a, "canUseDOM", isDocument), _a);
|
|
var updateTags = (type, tags) => {
|
|
const headElement = document.head || document.querySelector(
|
|
"head"
|
|
/* HEAD */
|
|
);
|
|
const tagNodes = headElement.querySelectorAll(`${type}[${HELMET_ATTRIBUTE}]`);
|
|
const oldTags = [].slice.call(tagNodes);
|
|
const newTags = [];
|
|
let indexToDelete;
|
|
if (tags && tags.length) {
|
|
tags.forEach((tag) => {
|
|
const newElement = document.createElement(type);
|
|
for (const attribute in tag) {
|
|
if (Object.prototype.hasOwnProperty.call(tag, attribute)) {
|
|
if (attribute === "innerHTML") {
|
|
newElement.innerHTML = tag.innerHTML;
|
|
} else if (attribute === "cssText") {
|
|
if (newElement.styleSheet) {
|
|
newElement.styleSheet.cssText = tag.cssText;
|
|
} else {
|
|
newElement.appendChild(document.createTextNode(tag.cssText));
|
|
}
|
|
} else {
|
|
const attr = attribute;
|
|
const value = typeof tag[attr] === "undefined" ? "" : tag[attr];
|
|
newElement.setAttribute(attribute, value);
|
|
}
|
|
}
|
|
}
|
|
newElement.setAttribute(HELMET_ATTRIBUTE, "true");
|
|
if (oldTags.some((existingTag, index) => {
|
|
indexToDelete = index;
|
|
return newElement.isEqualNode(existingTag);
|
|
})) {
|
|
oldTags.splice(indexToDelete, 1);
|
|
} else {
|
|
newTags.push(newElement);
|
|
}
|
|
});
|
|
}
|
|
oldTags.forEach((tag) => tag.parentNode?.removeChild(tag));
|
|
newTags.forEach((tag) => headElement.appendChild(tag));
|
|
return {
|
|
oldTags,
|
|
newTags
|
|
};
|
|
};
|
|
var updateAttributes = (tagName, attributes) => {
|
|
const elementTag = document.getElementsByTagName(tagName)[0];
|
|
if (!elementTag) {
|
|
return;
|
|
}
|
|
const helmetAttributeString = elementTag.getAttribute(HELMET_ATTRIBUTE);
|
|
const helmetAttributes = helmetAttributeString ? helmetAttributeString.split(",") : [];
|
|
const attributesToRemove = [...helmetAttributes];
|
|
const attributeKeys = Object.keys(attributes);
|
|
for (const attribute of attributeKeys) {
|
|
const value = attributes[attribute] || "";
|
|
if (elementTag.getAttribute(attribute) !== value) {
|
|
elementTag.setAttribute(attribute, value);
|
|
}
|
|
if (helmetAttributes.indexOf(attribute) === -1) {
|
|
helmetAttributes.push(attribute);
|
|
}
|
|
const indexToSave = attributesToRemove.indexOf(attribute);
|
|
if (indexToSave !== -1) {
|
|
attributesToRemove.splice(indexToSave, 1);
|
|
}
|
|
}
|
|
for (let i = attributesToRemove.length - 1; i >= 0; i -= 1) {
|
|
elementTag.removeAttribute(attributesToRemove[i]);
|
|
}
|
|
if (helmetAttributes.length === attributesToRemove.length) {
|
|
elementTag.removeAttribute(HELMET_ATTRIBUTE);
|
|
} else if (elementTag.getAttribute(HELMET_ATTRIBUTE) !== attributeKeys.join(",")) {
|
|
elementTag.setAttribute(HELMET_ATTRIBUTE, attributeKeys.join(","));
|
|
}
|
|
};
|
|
var updateTitle = (title, attributes) => {
|
|
if (typeof title !== "undefined" && document.title !== title) {
|
|
document.title = flattenArray(title);
|
|
}
|
|
updateAttributes("title", attributes);
|
|
};
|
|
var commitTagChanges = (newState, cb) => {
|
|
const {
|
|
baseTag,
|
|
bodyAttributes,
|
|
htmlAttributes,
|
|
linkTags,
|
|
metaTags,
|
|
noscriptTags,
|
|
onChangeClientState,
|
|
scriptTags,
|
|
styleTags,
|
|
title,
|
|
titleAttributes
|
|
} = newState;
|
|
updateAttributes("body", bodyAttributes);
|
|
updateAttributes("html", htmlAttributes);
|
|
updateTitle(title, titleAttributes);
|
|
const tagUpdates = {
|
|
baseTag: updateTags("base", baseTag),
|
|
linkTags: updateTags("link", linkTags),
|
|
metaTags: updateTags("meta", metaTags),
|
|
noscriptTags: updateTags("noscript", noscriptTags),
|
|
scriptTags: updateTags("script", scriptTags),
|
|
styleTags: updateTags("style", styleTags)
|
|
};
|
|
const addedTags = {};
|
|
const removedTags = {};
|
|
Object.keys(tagUpdates).forEach((tagType) => {
|
|
const { newTags, oldTags } = tagUpdates[tagType];
|
|
if (newTags.length) {
|
|
addedTags[tagType] = newTags;
|
|
}
|
|
if (oldTags.length) {
|
|
removedTags[tagType] = tagUpdates[tagType].oldTags;
|
|
}
|
|
});
|
|
if (cb) {
|
|
cb();
|
|
}
|
|
onChangeClientState(newState, addedTags, removedTags);
|
|
};
|
|
var _helmetCallback = null;
|
|
var handleStateChangeOnClient = (newState) => {
|
|
if (_helmetCallback) {
|
|
cancelAnimationFrame(_helmetCallback);
|
|
}
|
|
if (newState.defer) {
|
|
_helmetCallback = requestAnimationFrame(() => {
|
|
commitTagChanges(newState, () => {
|
|
_helmetCallback = null;
|
|
});
|
|
});
|
|
} else {
|
|
commitTagChanges(newState);
|
|
_helmetCallback = null;
|
|
}
|
|
};
|
|
var client_default = handleStateChangeOnClient;
|
|
var HelmetDispatcher = class extends import_react4.Component {
|
|
constructor() {
|
|
super(...arguments);
|
|
__publicField(this, "rendered", false);
|
|
}
|
|
shouldComponentUpdate(nextProps) {
|
|
return !(0, import_shallowequal.default)(nextProps, this.props);
|
|
}
|
|
componentDidUpdate() {
|
|
this.emitChange();
|
|
}
|
|
componentWillUnmount() {
|
|
const { helmetInstances } = this.props.context;
|
|
helmetInstances.remove(this);
|
|
this.emitChange();
|
|
}
|
|
emitChange() {
|
|
const { helmetInstances, setHelmet } = this.props.context;
|
|
let serverState = null;
|
|
const state = reducePropsToState(
|
|
helmetInstances.get().map((instance) => {
|
|
const props = { ...instance.props };
|
|
delete props.context;
|
|
return props;
|
|
})
|
|
);
|
|
if (HelmetProvider.canUseDOM) {
|
|
client_default(state);
|
|
} else if (server_default) {
|
|
serverState = server_default(state);
|
|
}
|
|
setHelmet(serverState);
|
|
}
|
|
// componentWillMount will be deprecated
|
|
// for SSR, initialize on first render
|
|
// constructor is also unsafe in StrictMode
|
|
init() {
|
|
if (this.rendered) {
|
|
return;
|
|
}
|
|
this.rendered = true;
|
|
const { helmetInstances } = this.props.context;
|
|
helmetInstances.add(this);
|
|
this.emitChange();
|
|
}
|
|
render() {
|
|
this.init();
|
|
return null;
|
|
}
|
|
};
|
|
var _a2;
|
|
var Helmet = (_a2 = class extends import_react.Component {
|
|
shouldComponentUpdate(nextProps) {
|
|
return !(0, import_react_fast_compare.default)(without(this.props, "helmetData"), without(nextProps, "helmetData"));
|
|
}
|
|
mapNestedChildrenToProps(child, nestedChildren) {
|
|
if (!nestedChildren) {
|
|
return null;
|
|
}
|
|
switch (child.type) {
|
|
case "script":
|
|
case "noscript":
|
|
return {
|
|
innerHTML: nestedChildren
|
|
};
|
|
case "style":
|
|
return {
|
|
cssText: nestedChildren
|
|
};
|
|
default:
|
|
throw new Error(
|
|
`<${child.type} /> elements are self-closing and can not contain children. Refer to our API for more information.`
|
|
);
|
|
}
|
|
}
|
|
flattenArrayTypeChildren(child, arrayTypeChildren, newChildProps, nestedChildren) {
|
|
return {
|
|
...arrayTypeChildren,
|
|
[child.type]: [
|
|
...arrayTypeChildren[child.type] || [],
|
|
{
|
|
...newChildProps,
|
|
...this.mapNestedChildrenToProps(child, nestedChildren)
|
|
}
|
|
]
|
|
};
|
|
}
|
|
mapObjectTypeChildren(child, newProps, newChildProps, nestedChildren) {
|
|
switch (child.type) {
|
|
case "title":
|
|
return {
|
|
...newProps,
|
|
[child.type]: nestedChildren,
|
|
titleAttributes: { ...newChildProps }
|
|
};
|
|
case "body":
|
|
return {
|
|
...newProps,
|
|
bodyAttributes: { ...newChildProps }
|
|
};
|
|
case "html":
|
|
return {
|
|
...newProps,
|
|
htmlAttributes: { ...newChildProps }
|
|
};
|
|
default:
|
|
return {
|
|
...newProps,
|
|
[child.type]: { ...newChildProps }
|
|
};
|
|
}
|
|
}
|
|
mapArrayTypeChildrenToProps(arrayTypeChildren, newProps) {
|
|
let newFlattenedProps = { ...newProps };
|
|
Object.keys(arrayTypeChildren).forEach((arrayChildName) => {
|
|
newFlattenedProps = {
|
|
...newFlattenedProps,
|
|
[arrayChildName]: arrayTypeChildren[arrayChildName]
|
|
};
|
|
});
|
|
return newFlattenedProps;
|
|
}
|
|
warnOnInvalidChildren(child, nestedChildren) {
|
|
(0, import_invariant.default)(
|
|
VALID_TAG_NAMES.some((name) => child.type === name),
|
|
typeof child.type === "function" ? `You may be attempting to nest <Helmet> components within each other, which is not allowed. Refer to our API for more information.` : `Only elements types ${VALID_TAG_NAMES.join(
|
|
", "
|
|
)} are allowed. Helmet does not support rendering <${child.type}> elements. Refer to our API for more information.`
|
|
);
|
|
(0, import_invariant.default)(
|
|
!nestedChildren || typeof nestedChildren === "string" || Array.isArray(nestedChildren) && !nestedChildren.some((nestedChild) => typeof nestedChild !== "string"),
|
|
`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.`
|
|
);
|
|
return true;
|
|
}
|
|
mapChildrenToProps(children, newProps) {
|
|
let arrayTypeChildren = {};
|
|
import_react.default.Children.forEach(children, (child) => {
|
|
if (!child || !child.props) {
|
|
return;
|
|
}
|
|
const { children: nestedChildren, ...childProps } = child.props;
|
|
const newChildProps = Object.keys(childProps).reduce((obj, key) => {
|
|
obj[HTML_TAG_MAP[key] || key] = childProps[key];
|
|
return obj;
|
|
}, {});
|
|
let { type } = child;
|
|
if (typeof type === "symbol") {
|
|
type = type.toString();
|
|
} else {
|
|
this.warnOnInvalidChildren(child, nestedChildren);
|
|
}
|
|
switch (type) {
|
|
case "Symbol(react.fragment)":
|
|
newProps = this.mapChildrenToProps(nestedChildren, newProps);
|
|
break;
|
|
case "link":
|
|
case "meta":
|
|
case "noscript":
|
|
case "script":
|
|
case "style":
|
|
arrayTypeChildren = this.flattenArrayTypeChildren(
|
|
child,
|
|
arrayTypeChildren,
|
|
newChildProps,
|
|
nestedChildren
|
|
);
|
|
break;
|
|
default:
|
|
newProps = this.mapObjectTypeChildren(child, newProps, newChildProps, nestedChildren);
|
|
break;
|
|
}
|
|
});
|
|
return this.mapArrayTypeChildrenToProps(arrayTypeChildren, newProps);
|
|
}
|
|
render() {
|
|
const { children, ...props } = this.props;
|
|
let newProps = { ...props };
|
|
let { helmetData } = props;
|
|
if (children) {
|
|
newProps = this.mapChildrenToProps(children, newProps);
|
|
}
|
|
if (helmetData && !(helmetData instanceof HelmetData)) {
|
|
const data = helmetData;
|
|
helmetData = new HelmetData(data.context, true);
|
|
delete newProps.helmetData;
|
|
}
|
|
return helmetData ? import_react.default.createElement(HelmetDispatcher, { ...newProps, context: helmetData.value }) : import_react.default.createElement(Context.Consumer, null, (context) => import_react.default.createElement(HelmetDispatcher, { ...newProps, context }));
|
|
}
|
|
}, __publicField(_a2, "defaultProps", {
|
|
defer: true,
|
|
encodeSpecialCharacters: true,
|
|
prioritizeSeoTags: false
|
|
}), _a2);
|
|
export {
|
|
Helmet,
|
|
HelmetData,
|
|
HelmetProvider
|
|
};
|
|
//# sourceMappingURL=react-helmet-async.js.map
|