diff --git a/dotcom-rendering/src/components/HostedContentPage.tsx b/dotcom-rendering/src/components/HostedContentPage.tsx new file mode 100644 index 00000000000..6e34f30aa46 --- /dev/null +++ b/dotcom-rendering/src/components/HostedContentPage.tsx @@ -0,0 +1,146 @@ +import { Global } from '@emotion/react'; +import { StrictMode } from 'react'; +import { HostedArticleLayout } from '../layouts/HostedArticleLayout'; +import { ArticleDesign } from '../lib/articleFormat'; +import { rootStyles } from '../lib/rootStyles'; +import { filterABTestSwitches } from '../model/enhance-switches'; +import type { HostedContent } from '../types/hostedContent'; +import type { RenderingTarget } from '../types/renderingTarget'; +import { useConfig } from './ConfigContext'; +import { DarkModeMessage } from './DarkModeMessage'; +import { FocusStyles } from './FocusStyles.importable'; +import { Island } from './Island'; +import { Lightbox } from './Lightbox'; +import { Metrics } from './Metrics.importable'; +import { SetABTests } from './SetABTests.importable'; +import { SkipTo } from './SkipTo'; + +interface BaseProps { + hostedContent: HostedContent; + renderingTarget: RenderingTarget; +} + +interface WebProps extends BaseProps { + renderingTarget: 'Web'; +} + +interface AppProps extends BaseProps { + renderingTarget: 'Apps'; +} + +const DecideHostedLayout = ({ + hostedContent, + renderingTarget, +}: WebProps | AppProps) => { + switch (hostedContent.design) { + case ArticleDesign.HostedArticle: + return ( + + ); + case ArticleDesign.HostedVideo: + case ArticleDesign.HostedGallery: + default: + return 'Not supported'; + } +}; + +/** + * @description + * Hosted Content pages are paid content written by third parties but hosted on theguardian.com domain. + * This is a high level wrapper for these pages on Dotcom. Sets strict mode and some globals + */ +export const HostedContentPage = (props: WebProps | AppProps) => { + const { + hostedContent: { design, display, theme, frontendData }, + renderingTarget, + } = props; + + const isWeb = renderingTarget === 'Web'; + const { darkModeAvailable } = useConfig(); + + const format = { + design, + display, + theme, + }; + + return ( + + + {isWeb && } + + + + + {renderingTarget === 'Web' && ( + <> + + + + + + + + + )} + + {renderingTarget === 'Web' && darkModeAvailable && ( + + Dark mode is a work-in-progress. +
+ You can{' '} + + opt out anytime + {' '} + if anything is unreadable or odd. +
+ )} + {renderingTarget === 'Apps' && !darkModeAvailable && ( + + We hope you are enjoying the updates we are implementing on + articles. Unfortunately, some are still missing a dark mode + view. Rest assured this will be fixed in a forthcoming beta + release. + + )} + + +
+ ); +}; diff --git a/dotcom-rendering/src/frontend/feArticle.ts b/dotcom-rendering/src/frontend/feArticle.ts index c62662da468..179244b368b 100644 --- a/dotcom-rendering/src/frontend/feArticle.ts +++ b/dotcom-rendering/src/frontend/feArticle.ts @@ -174,7 +174,10 @@ type FEDesign = | 'FullPageInteractiveDesign' | 'NewsletterSignupDesign' | 'TimelineDesign' - | 'ProfileDesign'; + | 'ProfileDesign' + | 'HostedArticle' + | 'HostedVideo' + | 'HostedGallery'; /** FEDisplay is the display information passed through from frontend (originating in the capi scala client) and dictates the display style of the content e.g. Immersive https://github.com/guardian/content-api-scala-client/blob/master/client/src/main/scala/com.gu.contentapi.client/utils/format/Display.scala */ diff --git a/dotcom-rendering/src/frontend/feHostedContent.ts b/dotcom-rendering/src/frontend/feHostedContent.ts index ef291843677..144eba407d0 100644 --- a/dotcom-rendering/src/frontend/feHostedContent.ts +++ b/dotcom-rendering/src/frontend/feHostedContent.ts @@ -1,27 +1,19 @@ -export interface FEHostedContent { - // general / shared - id: string; - url: string; - encodedUrl: string; - campaign?: HostedCampaign; - title: string; - mainImageUrl: string; - thumbnailUrl: string; - standfirst: string; - cta: HostedCallToAction; - name: string; - owner: string; - logo: HostedLogo; - fontColour: Colour; - // article - body?: string; - mainPicture?: string; - mainPictureCaption?: string; - // video - video?: HostedVideo; - // gallery - images: HostedGalleryImage[]; -} +import type { FEArticle } from './feArticle'; + +/** + * This type is what we receive from `frontend`, + * hence the FE prefix. + * + * WARNING: run `gen-schema` task if changing this to update the associated JSON + * schema definition. + */ +export type FEHostedContent = Omit< + FEArticle, + 'beaconURL' | 'blocks' | 'crossword' +>; + +/** +// Not sure if the following types are needed: type HostedCampaign = { id: string; @@ -75,3 +67,5 @@ type Encoding = { url: string; rawFormat: string; }; + + */ diff --git a/dotcom-rendering/src/frontend/schemas/feArticle.json b/dotcom-rendering/src/frontend/schemas/feArticle.json index da3341e7ef0..165285bcf74 100644 --- a/dotcom-rendering/src/frontend/schemas/feArticle.json +++ b/dotcom-rendering/src/frontend/schemas/feArticle.json @@ -4892,6 +4892,9 @@ "FeatureDesign", "FullPageInteractiveDesign", "GalleryDesign", + "HostedArticle", + "HostedGallery", + "HostedVideo", "InteractiveDesign", "InterviewDesign", "LetterDesign", diff --git a/dotcom-rendering/src/frontend/schemas/feFront.json b/dotcom-rendering/src/frontend/schemas/feFront.json index a0370aa7290..014681046d5 100644 --- a/dotcom-rendering/src/frontend/schemas/feFront.json +++ b/dotcom-rendering/src/frontend/schemas/feFront.json @@ -3925,6 +3925,9 @@ "FeatureDesign", "FullPageInteractiveDesign", "GalleryDesign", + "HostedArticle", + "HostedGallery", + "HostedVideo", "InteractiveDesign", "InterviewDesign", "LetterDesign", diff --git a/dotcom-rendering/src/frontend/schemas/feHostedContent.json b/dotcom-rendering/src/frontend/schemas/feHostedContent.json index f05667c1728..a936b4a2038 100644 --- a/dotcom-rendering/src/frontend/schemas/feHostedContent.json +++ b/dotcom-rendering/src/frontend/schemas/feHostedContent.json @@ -1,266 +1,5920 @@ { + "description": "This type is what we receive from `frontend`,\nhence the FE prefix.\n\nWARNING: run `gen-schema` task if changing this to update the associated JSON\nschema definition.", "type": "object", "properties": { - "id": { + "editionId": { + "$ref": "#/definitions/EditionId" + }, + "isAdFreeUser": { + "type": "boolean" + }, + "contentType": { + "type": "string" + }, + "pageId": { + "type": "string" + }, + "pillar": { + "$ref": "#/definitions/LegacyPillar" + }, + "webTitle": { + "type": "string" + }, + "headline": { + "type": "string" + }, + "standfirst": { + "type": "string" + }, + "affiliateLinksDisclaimer": { + "type": "string" + }, + "mainMediaElements": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "main": { + "type": "string" + }, + "keyEvents": { + "type": "array", + "items": { + "$ref": "#/definitions/Block" + } + }, + "pinnedPost": { + "$ref": "#/definitions/Block" + }, + "pagination": { + "$ref": "#/definitions/PaginationType" + }, + "byline": { + "type": "string" + }, + "author": {}, + "webPublicationDateDeprecated": { + "format": "date-time", + "type": "string" + }, + "webPublicationDate": { + "type": "string" + }, + "webPublicationDateDisplay": { + "type": "string" + }, + "webPublicationSecondaryDateDisplay": { + "type": "string" + }, + "editionLongForm": { + "type": "string" + }, + "version": { + "type": "number" + }, + "tags": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "type": { + "type": "string" + }, + "title": { + "type": "string" + }, + "twitterHandle": { + "type": "string" + }, + "paidContentType": { + "type": "string" + }, + "bylineImageUrl": { + "type": "string" + }, + "bylineLargeImageUrl": { + "type": "string" + }, + "podcast": { + "type": "object", + "properties": { + "subscriptionUrl": { + "type": "string" + }, + "spotifyUrl": { + "type": "string" + }, + "image": { + "type": "string" + } + } + } + }, + "required": [ + "id", + "title", + "type" + ] + } + }, + "format": { + "description": "FEFormat is the stringified version of Format passed through from Frontend.\nIt gets converted to the `@guardian/libs` format on platform", + "type": "object", + "properties": { + "design": { + "$ref": "#/definitions/FEDesign" + }, + "theme": { + "$ref": "#/definitions/FETheme" + }, + "display": { + "$ref": "#/definitions/FEDisplay" + } + }, + "required": [ + "design", + "display", + "theme" + ] + }, + "designType": { + "type": "string" + }, + "isImmersive": { + "type": "boolean" + }, + "sectionLabel": { + "type": "string" + }, + "sectionUrl": { + "type": "string" + }, + "sectionName": { + "type": "string" + }, + "subMetaSectionLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "subMetaKeywordLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "shouldHideAds": { + "type": "boolean" + }, + "openGraphData": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "twitterData": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "webURL": { + "type": "string" + }, + "linkedData": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": {} + } + }, + "config": { + "$ref": "#/definitions/ConfigType" + }, + "showBottomSocialButtons": { + "type": "boolean" + }, + "shouldHideReaderRevenue": { + "type": "boolean" + }, + "guardianBaseURL": { + "type": "string" + }, + "hasRelated": { + "type": "boolean" + }, + "publication": { + "type": "string" + }, + "hasStoryPackage": { + "type": "boolean" + }, + "storyPackage": { + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "trails": { + "type": "array", + "items": { + "$ref": "#/definitions/FETrailType" + } + } + }, + "required": [ + "heading", + "trails" + ] + }, + "onwards": { + "type": "array", + "items": { + "description": "Onwards", + "type": "object", + "properties": { + "heading": { + "type": "string" + }, + "trails": { + "type": "array", + "items": { + "$ref": "#/definitions/FETrailType" + } + }, + "description": { + "type": "string" + }, + "url": { + "type": "string" + }, + "onwardsSource": { + "$ref": "#/definitions/OnwardsSource" + }, + "format": { + "description": "FEFormat is the stringified version of Format passed through from Frontend.\nIt gets converted to the `@guardian/libs` format on platform", + "type": "object", + "properties": { + "design": { + "$ref": "#/definitions/FEDesign" + }, + "theme": { + "$ref": "#/definitions/FETheme" + }, + "display": { + "$ref": "#/definitions/FEDisplay" + } + }, + "required": [ + "design", + "display", + "theme" + ] + }, + "isCuratedContent": { + "type": "boolean" + } + }, + "required": [ + "format", + "heading", + "onwardsSource", + "trails" + ] + } + }, + "isCommentable": { + "type": "boolean" + }, + "commercialProperties": { + "$ref": "#/definitions/CommercialProperties" + }, + "starRating": { + "$ref": "#/definitions/StarRating" + }, + "audioArticleImage": { + "$ref": "#/definitions/ImageBlockElement" + }, + "trailPicture": { + "$ref": "#/definitions/ImageBlockElement" + }, + "trailText": { + "type": "string" + }, + "badge": { + "$ref": "#/definitions/FEArticleBadgeType" + }, + "nav": { + "$ref": "#/definitions/FENavType" + }, + "pageFooter": { + "$ref": "#/definitions/FooterType" + }, + "contributionsServiceUrl": { + "type": "string" + }, + "slotMachineFlags": { + "type": "string" + }, + "pageType": { + "type": "object", + "properties": { + "hasShowcaseMainElement": { + "type": "boolean" + }, + "isFront": { + "type": "boolean" + }, + "isLiveblog": { + "type": "boolean" + }, + "isMinuteArticle": { + "type": "boolean" + }, + "isPaidContent": { + "type": "boolean" + }, + "isPreview": { + "type": "boolean" + }, + "isSensitive": { + "type": "boolean" + } + }, + "required": [ + "hasShowcaseMainElement", + "isFront", + "isLiveblog", + "isMinuteArticle", + "isPaidContent", + "isPreview", + "isSensitive" + ] + }, + "matchUrl": { + "type": "string" + }, + "matchType": { + "$ref": "#/definitions/MatchType" + }, + "isSpecialReport": { + "type": "boolean" + }, + "isLegacyInteractive": { + "type": "boolean" + }, + "filterKeyEvents": { + "type": "boolean" + }, + "mostRecentBlockId": { + "type": "string" + }, + "promotedNewsletter": { + "type": "object", + "properties": { + "listId": { + "type": "number" + }, + "identityName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "successDescription": { + "type": "string" + }, + "theme": { + "type": "string" + }, + "group": { + "type": "string" + }, + "regionFocus": { + "type": "string" + }, + "illustrationCard": { + "type": "string" + } + }, + "required": [ + "description", + "frequency", + "group", + "identityName", + "listId", + "name", + "successDescription", + "theme" + ] + }, + "canonicalUrl": { + "type": "string" + }, + "showTableOfContents": { + "type": "boolean" + }, + "lang": { + "type": "string" + }, + "isRightToLeftLang": { + "type": "boolean" + } + }, + "required": [ + "canonicalUrl", + "commercialProperties", + "config", + "contentType", + "contributionsServiceUrl", + "designType", + "editionId", + "editionLongForm", + "filterKeyEvents", + "format", + "guardianBaseURL", + "hasRelated", + "hasStoryPackage", + "headline", + "isAdFreeUser", + "isCommentable", + "isImmersive", + "isSpecialReport", + "keyEvents", + "linkedData", + "main", + "mainMediaElements", + "nav", + "openGraphData", + "pageFooter", + "pageId", + "pageType", + "pillar", + "publication", + "sectionLabel", + "sectionUrl", + "shouldHideAds", + "shouldHideReaderRevenue", + "showBottomSocialButtons", + "showTableOfContents", + "standfirst", + "subMetaKeywordLinks", + "subMetaSectionLinks", + "tags", + "trailText", + "twitterData", + "version", + "webPublicationDate", + "webPublicationDateDeprecated", + "webPublicationDateDisplay", + "webPublicationSecondaryDateDisplay", + "webTitle", + "webURL" + ], + "definitions": { + "EditionId": { + "enum": [ + "AU", + "EUR", + "INT", + "UK", + "US" + ], + "type": "string" + }, + "LegacyPillar": { + "enum": [ + "culture", + "labs", + "lifestyle", + "news", + "opinion", + "sport" + ], + "type": "string" + }, + "FEElement": { + "anyOf": [ + { + "$ref": "#/definitions/AdPlaceholderBlockElement" + }, + { + "$ref": "#/definitions/AudioAtomBlockElement" + }, + { + "$ref": "#/definitions/AudioBlockElement" + }, + { + "$ref": "#/definitions/BlockquoteBlockElement" + }, + { + "$ref": "#/definitions/CaptionBlockElement" + }, + { + "$ref": "#/definitions/CalloutBlockElement" + }, + { + "$ref": "#/definitions/CalloutBlockElementV2" + }, + { + "$ref": "#/definitions/ReporterCalloutBlockElement" + }, + { + "$ref": "#/definitions/CartoonBlockElement" + }, + { + "$ref": "#/definitions/ChartAtomBlockElement" + }, + { + "$ref": "#/definitions/CodeBlockElement" + }, + { + "$ref": "#/definitions/CommentBlockElement" + }, + { + "$ref": "#/definitions/ContentAtomBlockElement" + }, + { + "$ref": "#/definitions/DisclaimerBlockElement" + }, + { + "$ref": "#/definitions/DividerBlockElement" + }, + { + "$ref": "#/definitions/DocumentBlockElement" + }, + { + "$ref": "#/definitions/EmbedBlockElement" + }, + { + "$ref": "#/definitions/ExplainerAtomBlockElement" + }, + { + "$ref": "#/definitions/GenericAtomBlockElement" + }, + { + "$ref": "#/definitions/GuideAtomBlockElement" + }, + { + "$ref": "#/definitions/GuVideoBlockElement" + }, + { + "$ref": "#/definitions/HighlightBlockElement" + }, + { + "$ref": "#/definitions/ImageBlockElement" + }, + { + "$ref": "#/definitions/InstagramBlockElement" + }, + { + "$ref": "#/definitions/InteractiveAtomBlockElement" + }, + { + "$ref": "#/definitions/InteractiveContentsBlockElement" + }, + { + "$ref": "#/definitions/InteractiveBlockElement" + }, + { + "$ref": "#/definitions/ItemLinkBlockElement" + }, + { + "$ref": "#/definitions/KeyTakeawaysBlockElement" + }, + { + "$ref": "#/definitions/LinkBlockElement" + }, + { + "$ref": "#/definitions/ListBlockElement" + }, + { + "$ref": "#/definitions/MapBlockElement" + }, + { + "$ref": "#/definitions/MediaAtomBlockElement" + }, + { + "$ref": "#/definitions/MiniProfilesBlockElement" + }, + { + "$ref": "#/definitions/MultiBylinesBlockElement" + }, + { + "$ref": "#/definitions/MultiImageBlockElement" + }, + { + "$ref": "#/definitions/NumberedTitleBlockElement" + }, + { + "$ref": "#/definitions/NewsletterSignupBlockElement" + }, + { + "$ref": "#/definitions/ProfileAtomBlockElement" + }, + { + "$ref": "#/definitions/PullquoteBlockElement" + }, + { + "$ref": "#/definitions/QAndAExplainerBlockElement" + }, + { + "$ref": "#/definitions/QABlockElement" + }, + { + "$ref": "#/definitions/QuizAtomBlockElement" + }, + { + "$ref": "#/definitions/RichLinkBlockElement" + }, + { + "$ref": "#/definitions/SoundcloudBlockElement" + }, + { + "$ref": "#/definitions/SpotifyBlockElement" + }, + { + "$ref": "#/definitions/StarRatingBlockElement" + }, + { + "$ref": "#/definitions/SubheadingBlockElement" + }, + { + "$ref": "#/definitions/TableBlockElement" + }, + { + "$ref": "#/definitions/TextBlockElement" + }, + { + "$ref": "#/definitions/TimelineAtomBlockElement" + }, + { + "$ref": "#/definitions/FETimelineBlockElement" + }, + { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.DCRTimelineBlockElement" + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { + "type": "string" + }, + "title": { + "type": "string" + }, + "label": { + "type": "string" + }, + "main": { + "$ref": "#/definitions/FEElement" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + } + }, + "required": [ + "body", + "date" + ] + } + } + }, + "required": [ + "_type", + "events" + ] + }, + { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.DCRSectionedTimelineBlockElement" + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "date": { + "type": "string" + }, + "title": { + "type": "string" + }, + "label": { + "type": "string" + }, + "main": { + "$ref": "#/definitions/FEElement" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + } + }, + "required": [ + "body", + "date" + ] + } + } + }, + "required": [ + "events", + "title" + ] + } + } + }, + "required": [ + "_type", + "sections" + ] + }, + { + "$ref": "#/definitions/TweetBlockElement" + }, + { + "$ref": "#/definitions/VideoBlockElement" + }, + { + "$ref": "#/definitions/VideoFacebookBlockElement" + }, + { + "$ref": "#/definitions/VideoVimeoBlockElement" + }, + { + "$ref": "#/definitions/VideoYoutubeBlockElement" + }, + { + "$ref": "#/definitions/VineBlockElement" + }, + { + "$ref": "#/definitions/YoutubeBlockElement" + }, + { + "$ref": "#/definitions/WitnessTypeBlockElement" + }, + { + "$ref": "#/definitions/CrosswordElement" + }, + { + "$ref": "#/definitions/ProductBlockElement" + }, + { + "$ref": "#/definitions/ProductCarouselElement" + } + ] + }, + "AdPlaceholderBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.AdPlaceholderBlockElement" + }, + "adPosition": { + "type": "number" + } + }, + "required": [ + "_type", + "adPosition" + ] + }, + "AudioAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.AudioAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "kicker": { + "type": "string" + }, + "title": { + "type": "string" + }, + "trackUrl": { + "type": "string" + }, + "duration": { + "type": "number" + }, + "coverUrl": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "coverUrl", + "duration", + "elementId", + "id", + "kicker", + "trackUrl" + ] + }, + "RoleType": { + "description": "Affects how an image is placed.\n\nAlso known as “weighting” in Composer, but we respect the CAPI naming.", + "enum": [ + "halfWidth", + "immersive", + "inline", + "showcase", + "supporting", + "thumbnail" + ], + "type": "string" + }, + "AudioBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.AudioBlockElement" + }, + "id": { + "type": "string" + }, + "elementId": { + "type": "string" + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/AudioAsset" + } + } + }, + "required": [ + "_type", + "assets", + "elementId" + ] + }, + "AudioAsset": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "fields": { + "type": "object", + "properties": { + "durationMinutes": { + "type": "string" + }, + "durationSeconds": { + "type": "string" + }, + "explicit": { + "type": "string" + }, + "source": { + "type": "string" + } + } + } + }, + "required": [ + "url" + ] + }, + "BlockquoteBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.BlockquoteBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "quoted": { + "type": "boolean" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "CaptionBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CaptionBlockElement" + }, + "elementId": { + "type": "string" + }, + "captionText": { + "type": "string" + }, + "padCaption": { + "type": "boolean" + }, + "credit": { + "type": "string" + }, + "displayCredit": { + "type": "boolean" + }, + "shouldLimitWidth": { + "type": "boolean" + }, + "isOverlaid": { + "type": "boolean" + } + }, + "required": [ + "_type", + "elementId" + ] + }, + "CalloutBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CalloutBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "calloutsUrl": { + "type": "string" + }, + "activeFrom": { + "type": "number" + }, + "activeUntil": { + "type": "number" + }, + "displayOnSensitive": { + "type": "boolean" + }, + "formId": { + "type": "number" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "tagName": { + "type": "string" + }, + "formFields": { + "type": "array", + "items": { + "$ref": "#/definitions/CampaignFieldType" + } + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "activeFrom", + "calloutsUrl", + "description", + "displayOnSensitive", + "elementId", + "formFields", + "formId", + "id", + "tagName", + "title" + ] + }, + "CampaignFieldType": { + "anyOf": [ + { + "$ref": "#/definitions/CampaignFieldText" + }, + { + "$ref": "#/definitions/CampaignFieldTextArea" + }, + { + "$ref": "#/definitions/CampaignFieldFile" + }, + { + "$ref": "#/definitions/CampaignFieldRadio" + }, + { + "$ref": "#/definitions/CampaignFieldCheckbox" + }, + { + "$ref": "#/definitions/CampaignFieldSelect" + } + ] + }, + "CampaignFieldText": { + "type": "object", + "properties": { + "type": { + "enum": [ + "email", + "phone", + "text" + ], + "type": "string" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "required", + "type" + ] + }, + "CampaignFieldTextArea": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "textarea" + }, + "minlength": { + "type": "number" + }, + "maxlength": { + "type": "number" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "required", + "type" + ] + }, + "CampaignFieldFile": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "file" + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "required", + "type" + ] + }, + "CampaignFieldRadio": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "radio" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "options", + "required", + "type" + ] + }, + "CampaignFieldCheckbox": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "checkbox" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "options", + "required", + "type" + ] + }, + "CampaignFieldSelect": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "select" + }, + "options": { + "type": "array", + "items": { + "type": "object", + "properties": { + "label": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "label", + "value" + ] + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "required": { + "type": "boolean" + }, + "textSize": { + "type": "number" + }, + "hideLabel": { + "type": "boolean" + }, + "hidden": { + "type": "boolean" + }, + "label": { + "type": "string" + } + }, + "required": [ + "id", + "label", + "name", + "options", + "required", + "type" + ] + }, + "CalloutBlockElementV2": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CalloutBlockElementV2" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "calloutsUrl": { + "type": "string" + }, + "activeFrom": { + "type": "number" + }, + "activeUntil": { + "type": "number" + }, + "displayOnSensitive": { + "type": "boolean" + }, + "formId": { + "type": "number" + }, + "prompt": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "tagName": { + "type": "string" + }, + "formFields": { + "type": "array", + "items": { + "$ref": "#/definitions/CampaignFieldType" + } + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isNonCollapsible": { + "type": "boolean" + }, + "contacts": { + "type": "array", + "items": { + "$ref": "#/definitions/CalloutContactType" + } + } + }, + "required": [ + "_type", + "activeFrom", + "calloutsUrl", + "description", + "displayOnSensitive", + "elementId", + "formFields", + "formId", + "id", + "isNonCollapsible", + "prompt", + "tagName", + "title" + ] + }, + "CalloutContactType": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + }, + "urlPrefix": { + "type": "string" + }, + "guidance": { + "type": "string" + } + }, + "required": [ + "name", + "urlPrefix", + "value" + ] + }, + "ReporterCalloutBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ReporterCalloutBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "activeFrom": { + "type": "number" + }, + "activeUntil": { + "type": "number" + }, + "displayOnSensitive": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "title": { + "type": "string" + }, + "subtitle": { + "type": "string" + }, + "intro": { + "type": "string" + }, + "mainTextHeading": { + "type": "string" + }, + "mainText": { + "type": "string" + }, + "emailContact": { + "type": "string" + }, + "messagingContact": { + "type": "string" + }, + "securedropContact": { + "type": "string" + }, + "endNote": { + "type": "string" + } + }, + "required": [ + "_type", + "displayOnSensitive", + "elementId", + "id", + "intro", + "mainText", + "mainTextHeading", + "subtitle", + "title" + ] + }, + "CartoonBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CartoonBlockElement" + }, + "elementId": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "variants": { + "type": "array", + "items": { + "type": "object", + "properties": { + "viewportSize": { + "enum": [ + "large", + "small" + ], + "type": "string" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/Image" + } + } + }, + "required": [ + "images", + "viewportSize" + ] + } + }, + "caption": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "displayCredit": { + "type": "boolean" + }, + "alt": { + "type": "string" + }, + "position": { + "description": "position is an index starting at 1 for all the images\nthat are “lightboxable”, including main media.\n\nIt is generated by `addImagePositions`", + "type": "number" + } + }, + "required": [ + "_type", + "elementId", + "role", + "variants" + ] + }, + "Image": { + "type": "object", + "properties": { + "index": { + "type": "number" + }, + "fields": { + "type": "object", + "properties": { + "height": { + "type": "string" + }, + "width": { + "type": "string" + }, + "aspectRatio": { + "type": "string" + }, + "isMaster": { + "type": "string" + }, + "source": { + "type": "string" + }, + "caption": { + "type": "string" + } + }, + "required": [ + "height", + "width" + ] + }, + "mediaType": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "fields", + "index", + "mediaType", + "url" + ] + }, + "ChartAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ChartAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "url": { + "type": "string" + }, + "html": { + "type": "string" + }, + "title": { + "type": "string" + }, + "css": { + "type": "string" + }, + "js": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "placeholderUrl": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html", + "id", + "title", + "url" + ] + }, + "CodeBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CodeBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "isMandatory": { + "type": "boolean" + }, + "language": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html", + "isMandatory" + ] + }, + "CommentBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CommentBlockElement" + }, + "elementId": { + "type": "string" + }, + "body": { + "type": "string" + }, + "avatarURL": { + "type": "string" + }, + "profileURL": { + "type": "string" + }, + "profileName": { + "type": "string" + }, + "permalink": { + "type": "string" + }, + "dateTime": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "avatarURL", + "body", + "dateTime", + "elementId", + "permalink", + "profileName", + "profileURL" + ] + }, + "ContentAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ContentAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "atomId": { + "type": "string" + } + }, + "required": [ + "_type", + "atomId", + "elementId" + ] + }, + "DisclaimerBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.DisclaimerBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "DividerBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.DividerBlockElement" + }, + "size": { + "enum": [ + "full", + "partial" + ], + "type": "string" + }, + "spaceAbove": { + "enum": [ + "loose", + "tight" + ], + "type": "string" + } + }, + "required": [ + "_type" + ] + }, + "DocumentBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.DocumentBlockElement" + }, + "elementId": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "title": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "isThirdPartyTracking" + ] + }, + "EmbedBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.EmbedBlockElement" + }, + "elementId": { + "type": "string" + }, + "safe": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "alt": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "html": { + "type": "string" + }, + "isMandatory": { + "type": "boolean" + }, + "caption": { + "type": "string" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html", + "isMandatory", + "isThirdPartyTracking" + ] + }, + "ExplainerAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ExplainerAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "body": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "body", + "elementId", + "id", + "title" + ] + }, + "GenericAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.GenericAtomBlockElement" + }, + "url": { + "type": "string" + }, + "placeholderUrl": { + "type": "string" + }, + "id": { + "type": "string" + }, + "html": { + "type": "string" + }, + "css": { + "type": "string" + }, + "js": { + "type": "string" + }, + "elementId": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "url" + ] + }, + "GuideAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.GuideAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "title": { + "type": "string" + }, + "img": { + "type": "string" + }, + "html": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "credit", + "elementId", + "html", + "id", + "label", + "title" + ] + }, + "GuVideoBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.GuVideoBlockElement" + }, + "elementId": { + "type": "string" + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/VideoAssets" + } + }, + "caption": { + "type": "string" + }, + "html": { + "type": "string" + }, + "source": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "imageMedia": { + "type": "object", + "properties": { + "allImages": { + "type": "array", + "items": { + "$ref": "#/definitions/Image" + } + } + }, + "required": [ + "allImages" + ] + }, + "originalUrl": { + "type": "string" + }, + "url": { + "type": "string" + } + }, + "required": [ + "_type", + "assets", + "caption", + "elementId", + "html", + "source" + ] + }, + "VideoAssets": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "mimeType": { + "type": "string" + }, + "dimensions": { + "type": "object", + "properties": { + "width": { + "type": "number" + }, + "height": { + "type": "number" + } + }, + "required": [ + "height", + "width" + ] + }, + "aspectRatio": { + "type": "string" + }, + "fields": { + "type": "object", + "properties": { + "source": { + "type": "string" + }, + "embeddable": { + "type": "string" + }, + "height": { + "type": "string" + }, + "width": { + "type": "string" + }, + "caption": { + "type": "string" + } + } + } + }, + "required": [ + "url" + ] + }, + "HighlightBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.HighlightBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "ImageBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ImageBlockElement" + }, + "elementId": { + "type": "string" + }, + "media": { + "type": "object", + "properties": { + "allImages": { + "type": "array", + "items": { + "$ref": "#/definitions/Image" + } + } + }, + "required": [ + "allImages" + ] + }, + "data": { + "type": "object", + "properties": { + "alt": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "copyright": { + "type": "string" + } + } + }, + "imageSources": { + "type": "array", + "items": { + "$ref": "#/definitions/ImageSource" + } + }, + "displayCredit": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "title": { + "type": "string" + }, + "starRating": { + "$ref": "#/definitions/StarRating" + }, + "isAvatar": { + "type": "boolean" + }, + "position": { + "description": "position is an index starting at 1 for all the images\nthat are “lightboxable”, including main media.\n\nIt is generated by `addImagePositions`", + "type": "number" + } + }, + "required": [ + "_type", + "data", + "elementId", + "imageSources", + "media", + "role" + ] + }, + "ImageSource": { + "type": "object", + "properties": { + "weighting": { + "$ref": "#/definitions/Weighting" + }, + "srcSet": { + "type": "array", + "items": { + "$ref": "#/definitions/SrcSetItem" + } + } + }, + "required": [ + "srcSet", + "weighting" + ] + }, + "Weighting": { + "description": "This duplicate type is unfortunate, but the image sources come lowercase\nNote, 'richLink' is used internally but does not exist upstream.", + "enum": [ + "halfwidth", + "immersive", + "inline", + "showcase", + "supporting", + "thumbnail" + ], + "type": "string" + }, + "SrcSetItem": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "width": { + "type": "number" + } + }, + "required": [ + "src", + "width" + ] + }, + "StarRating": { + "enum": [ + 0, + 1, + 2, + 3, + 4, + 5 + ], + "type": "number" + }, + "InstagramBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.InstagramBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "url": { + "type": "string" + }, + "hasCaption": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "hasCaption", + "html", + "isThirdPartyTracking", + "url" + ] + }, + "InteractiveAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.InteractiveAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "url": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "js": { + "type": "string" + }, + "html": { + "type": "string" + }, + "css": { + "type": "string" + }, + "placeholderUrl": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "elementId", + "id", + "title", + "url" + ] + }, + "InteractiveContentsBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.InteractiveContentsBlockElement" + }, + "elementId": { + "type": "string" + }, + "subheadingLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/SubheadingBlockElement" + } + }, + "endDocumentElementId": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "subheadingLinks" + ] + }, + "SubheadingBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.SubheadingBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "InteractiveBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.InteractiveBlockElement" + }, + "elementId": { + "type": "string" + }, + "url": { + "type": "string" + }, + "isMandatory": { + "type": "boolean" + }, + "scriptUrl": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "caption": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId" + ] + }, + "ItemLinkBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ItemLinkBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "KeyTakeawaysBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.KeyTakeawaysBlockElement" + }, + "keyTakeaways": { + "type": "array", + "items": { + "$ref": "#/definitions/KeyTakeaway" + } + } + }, + "required": [ + "_type", + "keyTakeaways" + ] + }, + "KeyTakeaway": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + } + }, + "required": [ + "body", + "title" + ] + }, + "LinkBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.LinkBlockElement" + }, + "url": { + "type": "string" + }, + "label": { + "type": "string" + }, + "linkType": { + "enum": [ + "ProductButton", + "StandardButton" + ], + "type": "string" + }, + "priority": { + "enum": [ + "Primary", + "Tertiary" + ], + "type": "string" + } + }, + "required": [ + "_type", + "label", + "linkType", + "url" + ] + }, + "ListBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ListBlockElement" + }, + "listElementType": { + "enum": [ + "KeyTakeaways", + "MiniProfiles", + "MultiByline", + "QAndAExplainer" + ], + "type": "string" + }, + "items": { + "type": "array", + "items": { + "$ref": "#/definitions/ListItem" + } + }, + "elementId": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "items", + "listElementType" + ] + }, + "ListItem": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "elements": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "bio": { + "type": "string" + }, + "endNote": { + "type": "string" + }, + "contributorImageOverrideUrl": { + "type": "string" + }, + "contributorIds": { + "type": "array", + "items": { + "type": "string" + } + }, + "byline": { + "type": "string" + }, + "bylineHtml": { + "type": "string" + } + }, + "required": [ + "elements" + ] + }, + "MapBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.MapBlockElement" + }, + "elementId": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "title": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "caption": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "embedUrl", + "height", + "isThirdPartyTracking", + "originalUrl", + "title", + "width" + ] + }, + "MediaAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.MediaAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/VideoAssets" + } + }, + "posterImage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "width": { + "type": "number" + } + }, + "required": [ + "url", + "width" + ] + } + }, + "title": { + "type": "string" + }, + "duration": { + "type": "number" + }, + "videoPlayerFormat": { + "$ref": "#/definitions/VideoPlayerFormat" + } + }, + "required": [ + "_type", + "assets", + "elementId", + "id" + ] + }, + "VideoPlayerFormat": { + "enum": [ + "Cinemagraph", + "Default", + "Loop" + ], + "type": "string" + }, + "MiniProfilesBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.MiniProfilesBlockElement" + }, + "miniProfiles": { + "type": "array", + "items": { + "$ref": "#/definitions/MiniProfile" + } + } + }, + "required": [ + "_type", + "miniProfiles" + ] + }, + "MiniProfile": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "bio": { + "type": "string" + }, + "endNote": { + "type": "string" + } + }, + "required": [ + "body", + "title" + ] + }, + "MultiBylinesBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.MultiBylinesBlockElement" + }, + "multiBylines": { + "type": "array", + "items": { + "$ref": "#/definitions/MultiByline" + } + } + }, + "required": [ + "_type", + "multiBylines" + ] + }, + "MultiByline": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "bio": { + "type": "string" + }, + "endNote": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "byline": { + "type": "string" + }, + "bylineHtml": { + "type": "string" + } + }, + "required": [ + "body", + "byline", + "bylineHtml", + "title" + ] + }, + "MultiImageBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.MultiImageBlockElement" + }, + "elementId": { + "type": "string" + }, + "images": { + "type": "array", + "items": { + "$ref": "#/definitions/ImageBlockElement" + } + }, + "caption": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "elementId", + "images" + ] + }, + "NumberedTitleBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.NumberedTitleBlockElement" + }, + "elementId": { + "type": "string" + }, + "position": { + "type": "number" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html", + "position" + ] + }, + "NewsletterSignupBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.NewsletterSignupBlockElement" + }, + "newsletter": { + "type": "object", + "properties": { + "listId": { + "type": "number" + }, + "identityName": { + "type": "string" + }, + "name": { + "type": "string" + }, + "description": { + "type": "string" + }, + "frequency": { + "type": "string" + }, + "successDescription": { + "type": "string" + }, + "theme": { + "type": "string" + }, + "group": { + "type": "string" + }, + "regionFocus": { + "type": "string" + }, + "illustrationCard": { + "type": "string" + } + }, + "required": [ + "description", + "frequency", + "group", + "identityName", + "listId", + "name", + "successDescription", + "theme" + ] + }, + "elementId": { + "type": "string" + } + }, + "required": [ + "_type", + "newsletter" + ] + }, + "ProfileAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ProfileAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "label": { + "type": "string" + }, + "title": { + "type": "string" + }, + "img": { + "type": "string" + }, + "html": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "credit", + "elementId", + "html", + "id", + "label", + "title" + ] + }, + "PullquoteBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.PullquoteBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "attribution": { + "type": "string" + }, + "isThirdPartyTracking": { + "type": "boolean" + } + }, + "required": [ + "_type", + "elementId", + "role" + ] + }, + "QAndAExplainerBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.QAndAExplainerBlockElement" + }, + "qAndAExplainers": { + "type": "array", + "items": { + "$ref": "#/definitions/QAndAExplainer" + } + } + }, + "required": [ + "_type", + "qAndAExplainers" + ] + }, + "QAndAExplainer": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + } + }, + "required": [ + "body", + "title" + ] + }, + "QABlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.QABlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "img": { + "type": "string" + }, + "html": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "credit", + "elementId", + "html", + "id", + "title" + ] + }, + "QuizAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.QuizAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "quizType": { + "enum": [ + "knowledge", + "personality" + ], + "type": "string" + }, + "id": { + "type": "string" + }, + "questions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "answers": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "text": { + "type": "string" + }, + "revealText": { + "type": "string" + }, + "isCorrect": { + "type": "boolean" + }, + "answerBuckets": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "answerBuckets", + "id", + "isCorrect", + "text" + ] + } + }, + "imageUrl": { + "type": "string" + }, + "imageAlt": { + "type": "string" + } + }, + "required": [ + "answers", + "id", + "text" + ] + } + }, + "resultBuckets": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + } + }, + "required": [ + "description", + "id", + "title" + ] + } + }, + "resultGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "shareText": { + "type": "string" + }, + "minScore": { + "type": "number" + }, + "id": { + "type": "string" + } + }, + "required": [ + "id", + "minScore", + "shareText", + "title" + ] + } + } + }, + "required": [ + "_type", + "elementId", + "id", + "questions", + "quizType", + "resultBuckets", + "resultGroups" + ] + }, + "RichLinkBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.RichLinkBlockElement" + }, + "elementId": { + "type": "string" + }, + "url": { + "type": "string" + }, + "text": { + "type": "string" + }, + "prefix": { + "type": "string" + }, + "role": { + "enum": [ + "halfWidth", + "immersive", + "inline", + "richLink", + "showcase", + "supporting", + "thumbnail" + ], + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "prefix", + "text", + "url" + ] + }, + "SoundcloudBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.SoundcloudBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "id": { + "type": "string" + }, + "isTrack": { + "type": "boolean" + }, + "isMandatory": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html", + "id", + "isMandatory", + "isThirdPartyTracking", + "isTrack" + ] + }, + "SpotifyBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.SpotifyBlockElement" + }, + "elementId": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "title": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "caption": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "isThirdPartyTracking" + ] + }, + "StarRatingBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.StarRatingBlockElement" + }, + "elementId": { + "type": "string" + }, + "rating": { + "$ref": "#/definitions/StarRating" + }, + "size": { + "$ref": "#/definitions/RatingSizeType" + } + }, + "required": [ + "_type", + "elementId", + "rating", + "size" + ] + }, + "RatingSizeType": { + "enum": [ + "large", + "medium", + "small" + ], + "type": "string" + }, + "TableBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.TableBlockElement" + }, + "elementId": { + "type": "string" + }, + "isMandatory": { + "type": "boolean" + }, + "html": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "elementId", + "html", + "isMandatory" + ] + }, + "TextBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.TextBlockElement" + }, + "elementId": { + "type": "string" + }, + "dropCap": { + "enum": [ + "off", + "on" + ], + "type": "string" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "html" + ] + }, + "TimelineAtomBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.TimelineAtomBlockElement" + }, + "elementId": { + "type": "string" + }, + "id": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "$ref": "#/definitions/TimelineAtomEvent" + } + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "elementId", + "events", + "id", + "title" + ] + }, + "TimelineAtomEvent": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "date": { + "type": "string" + }, + "unixDate": { + "type": "number" + }, + "body": { + "type": "string" + }, + "toDate": { + "type": "string" + }, + "toUnixDate": { + "type": "number" + } + }, + "required": [ + "date", + "title", + "unixDate" + ] + }, + "FETimelineBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.TimelineBlockElement" + }, + "elementId": { + "type": "string" + }, + "sections": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "events": { + "type": "array", + "items": { + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "date": { + "type": "string" + }, + "label": { + "type": "string" + }, + "main": { + "$ref": "#/definitions/FEElement" + }, + "body": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + } + }, + "required": [ + "body" + ] + } + } + }, + "required": [ + "events" + ] + } + } + }, + "required": [ + "_type", + "elementId", + "sections" + ] + }, + "TweetBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.TweetBlockElement" + }, + "elementId": { + "type": "string" + }, + "html": { + "type": "string" + }, + "url": { + "type": "string" + }, + "id": { + "type": "string" + }, + "hasMedia": { + "type": "boolean" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "hasMedia", + "html", + "id", + "isThirdPartyTracking", + "url" + ] + }, + "VideoBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.VideoBlockElement" + }, + "elementId": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "isThirdPartyTracking" + ] + }, + "VideoFacebookBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.VideoFacebookBlockElement" + }, + "elementId": { + "type": "string" + }, + "url": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "caption": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "height", + "isThirdPartyTracking", + "url", + "width" + ] + }, + "VideoVimeoBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.VideoVimeoBlockElement" + }, + "elementId": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "url": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "caption": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "title": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "height", + "isThirdPartyTracking", + "url", + "width" + ] + }, + "VideoYoutubeBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.VideoYoutubeBlockElement" + }, + "elementId": { + "type": "string" + }, + "embedUrl": { + "type": "string" + }, + "url": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "caption": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "title": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "height", + "isThirdPartyTracking", + "originalUrl", + "url", + "width" + ] + }, + "VineBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.VineBlockElement" + }, + "elementId": { + "type": "string" + }, + "url": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "originalUrl": { + "type": "string" + }, + "title": { + "type": "string" + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "elementId", + "height", + "isThirdPartyTracking", + "originalUrl", + "title", + "url", + "width" + ] + }, + "YoutubeBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.YoutubeBlockElement" + }, + "assetId": { + "type": "string" + }, + "mediaTitle": { + "type": "string" + }, + "id": { + "type": "string" + }, + "elementId": { + "type": "string" + }, + "channelId": { + "type": "string" + }, + "duration": { + "type": "number" + }, + "posterImage": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "width": { + "type": "number" + } + }, + "required": [ + "url", + "width" + ] + } + }, + "expired": { + "type": "boolean" + }, + "overrideImage": { + "type": "string" + }, + "altText": { + "type": "string" + }, + "role": { + "$ref": "#/definitions/RoleType" + } + }, + "required": [ + "_type", + "assetId", + "elementId", + "expired", + "id", + "mediaTitle" + ] + }, + "WitnessTypeBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.WitnessBlockElement" + }, + "elementId": { + "type": "string" + }, + "assets": { + "type": "array", + "items": { + "$ref": "#/definitions/WitnessAssetType" + } + }, + "isThirdPartyTracking": { + "type": "boolean" + }, + "witnessTypeData": { + "anyOf": [ + { + "$ref": "#/definitions/WitnessTypeDataImage" + }, + { + "$ref": "#/definitions/WitnessTypeDataVideo" + }, + { + "$ref": "#/definitions/WitnessTypeDataText" + } + ] + }, + "source": { + "type": "string" + }, + "sourceDomain": { + "type": "string" + } + }, + "required": [ + "_type", + "assets", + "elementId", + "isThirdPartyTracking", + "witnessTypeData" + ] + }, + "WitnessAssetType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "Image" + }, + "mimeType": { + "type": "string" + }, + "file": { + "type": "string" + }, + "typeData": { + "type": "object", + "properties": { + "name": { + "type": "string" + } + } + } + }, + "required": [ + "type" + ] + }, + "WitnessTypeDataImage": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.WitnessTypeDataImage" + }, + "type": { + "type": "string", + "const": "image" + }, + "alt": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "mediaId": { + "type": "string" + }, + "photographer": { + "type": "string" + }, + "authorUsername": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "source": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + }, + "dateCreated": { + "type": "string" + }, + "apiUrl": { + "type": "string" + }, + "authorName": { + "type": "string" + }, + "witnessEmbedType": { + "type": "string" + }, + "html": { + "type": "string" + }, + "authorWitnessProfileUrl": { + "type": "string" + } + }, + "required": [ + "_type", + "alt", + "apiUrl", + "authorName", + "authorUsername", + "authorWitnessProfileUrl", + "dateCreated", + "mediaId", + "originalUrl", + "photographer", + "source", + "title", + "type", + "url", + "witnessEmbedType" + ] + }, + "WitnessTypeDataVideo": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.WitnessTypeDataVideo" + }, + "type": { + "type": "string", + "const": "video" + }, + "description": { + "type": "string" + }, + "youtubeHtml": { + "type": "string" + }, + "youtubeDescription": { + "type": "string" + }, + "youtubeUrl": { + "type": "string" + }, + "width": { + "type": "number" + }, + "youtubeSource": { + "type": "string" + }, + "youtubeAuthorName": { + "type": "string" + }, + "height": { + "type": "number" + }, + "youtubeTitle": { + "type": "string" + }, + "authorUsername": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "source": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + }, + "dateCreated": { + "type": "string" + }, + "apiUrl": { + "type": "string" + }, + "authorName": { + "type": "string" + }, + "witnessEmbedType": { + "type": "string" + }, + "html": { + "type": "string" + }, + "authorWitnessProfileUrl": { + "type": "string" + } + }, + "required": [ + "_type", + "apiUrl", + "authorName", + "authorUsername", + "authorWitnessProfileUrl", + "dateCreated", + "description", + "height", + "originalUrl", + "source", + "title", + "type", + "url", + "width", + "witnessEmbedType", + "youtubeAuthorName", + "youtubeDescription", + "youtubeHtml", + "youtubeSource", + "youtubeTitle", + "youtubeUrl" + ] + }, + "WitnessTypeDataText": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.WitnessTypeDataText" + }, + "type": { + "type": "string", + "const": "text" + }, + "description": { + "type": "string" + }, + "authorUsername": { + "type": "string" + }, + "originalUrl": { + "type": "string" + }, + "source": { + "type": "string" + }, + "title": { + "type": "string" + }, + "url": { + "type": "string" + }, + "dateCreated": { + "type": "string" + }, + "apiUrl": { + "type": "string" + }, + "authorName": { + "type": "string" + }, + "witnessEmbedType": { + "type": "string" + }, + "authorWitnessProfileUrl": { + "type": "string" + }, + "html": { + "type": "string" + } + }, + "required": [ + "_type", + "apiUrl", + "authorName", + "authorUsername", + "authorWitnessProfileUrl", + "dateCreated", + "description", + "originalUrl", + "source", + "title", + "type", + "url", + "witnessEmbedType" + ] + }, + "CrosswordElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.CrosswordElement" + }, + "crossword": { + "type": "object", + "properties": { + "creator": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "webUrl": { + "type": "string" + } + }, + "required": [ + "name", + "webUrl" + ] + }, + "crosswordType": { + "enum": [ + "cryptic", + "everyman", + "mini", + "prize", + "quick", + "quick-cryptic", + "quiptic", + "special", + "speedy", + "sunday-quick", + "weekend" + ], + "type": "string" + }, + "date": { + "type": "number" + }, + "dateSolutionAvailable": { + "type": "number" + }, + "dimensions": { + "type": "object", + "properties": { + "rows": { + "type": "number" + }, + "cols": { + "type": "number" + } + }, + "required": [ + "cols", + "rows" + ] + }, + "entries": { + "type": "array", + "items": { + "$ref": "#/definitions/CAPIEntry" + } + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "number": { + "type": "number" + }, + "pdf": { + "type": "string" + }, + "solutionAvailable": { + "type": "boolean" + }, + "webPublicationDate": { + "type": "number" + }, + "instructions": { + "type": "string" + } + }, + "required": [ + "crosswordType", + "date", + "dimensions", + "entries", + "id", + "name", + "number", + "solutionAvailable" + ] + } + }, + "required": [ + "_type", + "crossword" + ] + }, + "CAPIEntry": { + "allOf": [ + { + "type": "object", + "properties": { + "id": { + "anyOf": [ + { + "type": "string", + "pattern": "^[0-9]*-across$" + }, + { + "type": "string", + "pattern": "^[0-9]*-down$" + } + ] + }, + "group": { + "type": "array", + "items": [ + { + "anyOf": [ + { + "type": "string", + "pattern": "^[0-9]*-across$" + }, + { + "type": "string", + "pattern": "^[0-9]*-down$" + } + ] + } + ], + "minItems": 1, + "additionalItems": { + "anyOf": [ + { + "type": "string", + "pattern": "^[0-9]*-across$" + }, + { + "type": "string", + "pattern": "^[0-9]*-down$" + } + ] + } + }, + "number": { + "type": "number" + } + }, + "required": [ + "group", + "id", + "number" + ] + }, + { + "type": "object", + "properties": { + "direction": { + "$ref": "#/definitions/Direction" + }, + "position": { + "$ref": "#/definitions/Coords", + "description": "Coords of first cell" + }, + "clue": { + "description": "The clue for the current entry", + "type": "string" + }, + "humanNumber": { + "description": "The number for the clue", + "type": "string" + }, + "solution": { + "description": "The solution to the entry's clue", + "type": "string" + }, + "length": { + "description": "The length of the solution (we don't always have a solution)", + "type": "number" + }, + "separatorLocations": { + "$ref": "#/definitions/Record", + "description": "Separators for multi-part solutions e.g.\n- ready,steady,go\n- tofu-eating" + } + }, + "required": [ + "clue", + "direction", + "humanNumber", + "length", + "position", + "separatorLocations" + ] + } + ] + }, + "Direction": { + "enum": [ + "across", + "down" + ], + "type": "string" + }, + "Coords": { + "type": "object", + "properties": { + "x": { + "type": "number" + }, + "y": { + "type": "number" + } + }, + "required": [ + "x", + "y" + ] + }, + "Record": { + "type": "object" + }, + "ProductBlockElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ProductBlockElement" + }, + "elementId": { + "type": "string" + }, + "brandName": { + "type": "string" + }, + "starRating": { + "$ref": "#/definitions/ProductStarRating" + }, + "productName": { + "type": "string" + }, + "image": { + "$ref": "#/definitions/ProductImage" + }, + "secondaryHeadingHtml": { + "type": "string" + }, + "secondaryHeadingText": { + "type": "string" + }, + "primaryHeadingHtml": { + "type": "string" + }, + "primaryHeadingText": { + "type": "string" + }, + "customAttributes": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "value": { + "type": "string" + } + }, + "required": [ + "name", + "value" + ] + } + }, + "content": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "h2Id": { + "type": "string" + }, + "displayType": { + "$ref": "#/definitions/ProductDisplayType" + }, + "productCtas": { + "type": "array", + "items": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "text": { + "type": "string" + }, + "retailer": { + "type": "string" + }, + "price": { + "type": "string" + } + }, + "required": [ + "price", + "retailer", + "text", + "url" + ] + } + }, + "lowestPrice": { + "type": "string" + } + }, + "required": [ + "_type", + "brandName", + "content", + "customAttributes", + "displayType", + "elementId", + "primaryHeadingHtml", + "productCtas", + "productName", + "secondaryHeadingHtml", + "starRating" + ] + }, + "ProductStarRating": { + "enum": [ + "0", + "1", + "2", + "3", + "4", + "5", + "none-selected" + ], + "type": "string" + }, + "ProductImage": { + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "caption": { + "type": "string" + }, + "credit": { + "type": "string" + }, + "alt": { + "type": "string" + }, + "displayCredit": { + "type": "boolean" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + } + }, + "required": [ + "alt", + "caption", + "credit", + "displayCredit", + "height", + "url", + "width" + ] + }, + "ProductDisplayType": { + "enum": [ + "InlineOnly", + "InlineWithProductCard", + "ProductCardOnly" + ], + "type": "string" + }, + "ProductCarouselElement": { + "type": "object", + "properties": { + "_type": { + "type": "string", + "const": "model.dotcomrendering.pageElements.ProductCarouselElement" + }, + "matchedProducts": { + "type": "array", + "items": { + "$ref": "#/definitions/ProductBlockElement" + } + } + }, + "required": [ + "_type", + "matchedProducts" + ] + }, + "Block": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "elements": { + "type": "array", + "items": { + "$ref": "#/definitions/FEElement" + } + }, + "attributes": { + "$ref": "#/definitions/Attributes" + }, + "blockCreatedOn": { + "type": "number" + }, + "blockCreatedOnDisplay": { + "type": "string" + }, + "blockLastUpdated": { + "type": "number" + }, + "blockLastUpdatedDisplay": { + "type": "string" + }, + "title": { + "type": "string" + }, + "blockFirstPublished": { + "type": "number" + }, + "blockFirstPublishedDisplay": { + "type": "string" + }, + "blockFirstPublishedDisplayNoTimezone": { + "type": "string" + }, + "primaryDateLine": { + "type": "string" + }, + "secondaryDateLine": { + "type": "string" + }, + "createdOn": { + "type": "number" + }, + "createdOnDisplay": { + "type": "string" + }, + "lastUpdated": { + "type": "number" + }, + "lastUpdatedDisplay": { + "type": "string" + }, + "firstPublished": { + "type": "number" + }, + "firstPublishedDisplay": { + "type": "string" + }, + "contributors": { + "type": "array", + "items": { + "$ref": "#/definitions/BlockContributor" + } + } + }, + "required": [ + "attributes", + "elements", + "id", + "primaryDateLine", + "secondaryDateLine" + ] + }, + "Attributes": { + "type": "object", + "properties": { + "pinned": { + "type": "boolean" + }, + "summary": { + "type": "boolean" + }, + "keyEvent": { + "type": "boolean" + }, + "membershipPlaceholder": { + "$ref": "#/definitions/MembershipPlaceholder" + } + }, + "required": [ + "keyEvent", + "pinned", + "summary" + ] + }, + "MembershipPlaceholder": { + "type": "object", + "properties": { + "campaignCode": { + "type": "string" + } + } + }, + "BlockContributor": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "imageUrl": { + "type": "string" + }, + "largeImageUrl": { + "type": "string" + } + }, + "required": [ + "name" + ] + }, + "PaginationType": { + "type": "object", + "properties": { + "currentPage": { + "type": "number" + }, + "totalPages": { + "type": "number" + }, + "newest": { + "type": "string" + }, + "newer": { + "type": "string" + }, + "oldest": { + "type": "string" + }, + "older": { + "type": "string" + } + }, + "required": [ + "currentPage", + "totalPages" + ] + }, + "FEDesign": { + "description": "FEDesign is what frontend gives (originating in the capi scala client) us on the Format field\nhttps://github.com/guardian/content-api-scala-client/blob/master/client/src/main/scala/com.gu.contentapi.client/utils/format/Design.scala", + "enum": [ + "AnalysisDesign", + "ArticleDesign", + "AudioDesign", + "CommentDesign", + "CrosswordDesign", + "DeadBlogDesign", + "EditorialDesign", + "ExplainerDesign", + "FeatureDesign", + "FullPageInteractiveDesign", + "GalleryDesign", + "HostedArticle", + "HostedGallery", + "HostedVideo", + "InteractiveDesign", + "InterviewDesign", + "LetterDesign", + "LiveBlogDesign", + "MatchReportDesign", + "NewsletterSignupDesign", + "ObituaryDesign", + "PhotoEssayDesign", + "PictureDesign", + "ProfileDesign", + "QuizDesign", + "RecipeDesign", + "ReviewDesign", + "TimelineDesign", + "VideoDesign" + ], + "type": "string" + }, + "FETheme": { + "enum": [ + "CulturePillar", + "Labs", + "LifestylePillar", + "NewsPillar", + "OpinionPillar", + "SpecialReportAltTheme", + "SpecialReportTheme", + "SportPillar" + ], + "type": "string" + }, + "FEDisplay": { + "description": "FEDisplay is the display information passed through from frontend (originating in the capi scala client) and dictates the display style of the content e.g. Immersive\nhttps://github.com/guardian/content-api-scala-client/blob/master/client/src/main/scala/com.gu.contentapi.client/utils/format/Display.scala", + "enum": [ + "ImmersiveDisplay", + "NumberedListDisplay", + "ShowcaseDisplay", + "StandardDisplay" + ], + "type": "string" + }, + "FELinkType": { + "description": "Data types for the API request bodies from clients that require transformation before internal use.\nWhere data types are coming from Frontend we try to use the 'FE' prefix.\nPrior to this we used 'CAPI' as a prefix which wasn't entirely accurate, and some data structures never received the prefix, meaning some are still missing it.", + "type": "object", + "properties": { + "url": { + "type": "string" + }, + "title": { + "type": "string" + }, + "longTitle": { + "type": "string" + }, + "iconName": { + "type": "string" + }, + "children": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "pillar": { + "$ref": "#/definitions/LegacyPillar" + }, + "more": { + "type": "boolean" + }, + "classList": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "title", + "url" + ] + }, + "ConfigType": { + "description": "the config model will contain useful app/site\nlevel data. Although currently derived from the config model\nconstructed in frontend and passed to dotcom-rendering\nthis data could eventually be defined in dotcom-rendering", + "type": "object", + "properties": { + "dcrCouldRender": { + "type": "boolean" + }, + "ajaxUrl": { + "type": "string" + }, + "sentryPublicApiKey": { + "type": "string" + }, + "sentryHost": { + "type": "string" + }, + "dcrSentryDsn": { + "type": "string" + }, + "switches": { + "$ref": "#/definitions/Switches" + }, + "abTests": { + "description": "Narrowest representation of the server-side tests\nobject shape, which is [defined in `frontend`](https://github.com/guardian/frontend/blob/23743723030a041e4f4f59fa265ee2be0bb51825/common/app/experiments/ExperimentsDefinition.scala#L24-L26).\n\n**Note:** This type is not support by JSON-schema, it evaluates as `object`", + "type": "object" + }, + "serverSideABTests": { + "$ref": "#/definitions/Record" + }, + "dfpAccountId": { + "type": "string" + }, + "commercialBundleUrl": { + "type": "string" + }, + "revisionNumber": { + "type": "string" + }, + "shortUrlId": { + "type": "string" + }, + "isDev": { + "type": "boolean" + }, + "googletagUrl": { + "type": "string" + }, + "stage": { + "$ref": "#/definitions/StageType" + }, + "frontendAssetsFullURL": { + "type": "string" + }, + "adUnit": { + "type": "string" + }, + "isSensitive": { + "type": "boolean" + }, + "videoDuration": { + "type": "number" + }, + "edition": { + "$ref": "#/definitions/EditionId" + }, + "section": { + "type": "string" + }, + "source": { + "type": "string" + }, + "sharedAdTargeting": { + "$ref": "#/definitions/SharedAdTargeting" + }, + "isPaidContent": { + "type": "boolean" + }, + "keywordIds": { + "type": "string" + }, + "showRelatedContent": { + "type": "boolean" + }, + "shouldHideReaderRevenue": { + "type": "boolean" + }, + "idApiUrl": { + "type": "string" + }, + "discussionApiUrl": { + "type": "string" + }, + "discussionD2Uid": { + "type": "string" + }, + "discussionApiClientHeader": { + "type": "string" + }, + "isPhotoEssay": { + "type": "boolean" + }, + "references": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + }, + "host": { + "type": "string" + }, + "idUrl": { + "type": "string" + }, + "mmaUrl": { + "type": "string" + }, + "brazeApiKey": { + "type": "string" + }, + "ipsosTag": { + "type": "string" + }, + "isLiveBlog": { + "type": "boolean" + }, + "isLive": { + "type": "boolean" + }, + "isPreview": { + "type": "boolean" + }, + "googleRecaptchaSiteKey": { + "type": "string" + }, + "googleRecaptchaSiteKeyVisible": { + "type": "string" + }, + "pageId": { + "type": "string" + }, + "webPublicationDate": { + "type": "number" + }, + "headline": { + "type": "string" + }, + "author": { + "type": "string" + }, + "keywords": { + "type": "string" + }, + "series": { + "type": "string" + }, + "toneIds": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "ampIframeUrl": { + "type": "string" + }, + "hasLiveBlogTopAd": { + "type": "boolean" + }, + "hasSurveyAd": { + "type": "boolean" + } + }, + "required": [ + "abTests", + "adUnit", + "ajaxUrl", + "ampIframeUrl", + "commercialBundleUrl", + "contentType", + "dcrSentryDsn", + "dfpAccountId", + "discussionApiClientHeader", + "discussionApiUrl", + "discussionD2Uid", + "edition", + "frontendAssetsFullURL", + "googletagUrl", + "idApiUrl", + "isSensitive", + "keywordIds", + "pageId", + "revisionNumber", + "section", + "sentryHost", + "sentryPublicApiKey", + "serverSideABTests", + "sharedAdTargeting", + "shortUrlId", + "showRelatedContent", + "stage", + "switches" + ] + }, + "Switches": { + "type": "object", + "additionalProperties": { + "type": "boolean" + } + }, + "Record": { + "type": "object" + }, + "StageType": { + "enum": [ + "CODE", + "DEV", + "PROD" + ], "type": "string" }, - "url": { - "type": "string" + "SharedAdTargeting": { + "type": "object" + }, + "FETrailType": { + "type": "object", + "properties": { + "format": { + "description": "FEFormat is the stringified version of Format passed through from Frontend.\nIt gets converted to the `@guardian/libs` format on platform", + "type": "object", + "properties": { + "design": { + "$ref": "#/definitions/FEDesign" + }, + "theme": { + "$ref": "#/definitions/FETheme" + }, + "display": { + "$ref": "#/definitions/FEDisplay" + } + }, + "required": [ + "design", + "display", + "theme" + ] + }, + "designType": { + "type": "string" + }, + "pillar": { + "type": "string" + }, + "carouselImages": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "isLiveBlog": { + "type": "boolean" + }, + "masterImage": { + "type": "string" + }, + "image": { + "type": "string" + }, + "url": { + "type": "string" + }, + "headline": { + "type": "string" + }, + "webPublicationDate": { + "type": "string" + }, + "avatarUrl": { + "type": "string" + }, + "mediaDuration": { + "type": "number" + }, + "ageWarning": { + "type": "string" + }, + "byline": { + "type": "string" + }, + "showByline": { + "type": "boolean" + }, + "kickerText": { + "type": "string" + }, + "shortUrl": { + "type": "string" + }, + "commentCount": { + "type": "number" + }, + "starRating": { + "$ref": "#/definitions/StarRating" + }, + "linkText": { + "type": "string" + }, + "branding": { + "$ref": "#/definitions/Branding" + }, + "isSnap": { + "type": "boolean" + }, + "isCrossword": { + "type": "boolean" + }, + "snapData": { + "type": "object", + "properties": { + "embedHtml": { + "type": "string" + }, + "embedCss": { + "type": "string" + }, + "embedJs": { + "type": "string" + } + } + }, + "showQuotedHeadline": { + "type": "boolean" + }, + "discussion": { + "type": "object", + "properties": { + "isCommentable": { + "type": "boolean" + }, + "isClosedForComments": { + "type": "boolean" + }, + "discussionId": { + "type": "string" + } + }, + "required": [ + "isClosedForComments", + "isCommentable" + ] + }, + "mainMedia": { + "$ref": "#/definitions/MainMedia" + }, + "trailText": { + "type": "string" + }, + "galleryCount": { + "type": "number" + } + }, + "required": [ + "format", + "headline", + "url" + ] + }, + "Branding": { + "type": "object", + "properties": { + "brandingType": { + "$ref": "#/definitions/BrandingType" + }, + "sponsorName": { + "type": "string" + }, + "logo": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "link": { + "type": "string" + }, + "label": { + "type": "string" + }, + "dimensions": { + "type": "object", + "properties": { + "width": { + "type": "number" + }, + "height": { + "type": "number" + } + }, + "required": [ + "height", + "width" + ] + } + }, + "required": [ + "dimensions", + "label", + "link", + "src" + ] + }, + "aboutThisLink": { + "type": "string" + }, + "logoForDarkBackground": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "link": { + "type": "string" + }, + "label": { + "type": "string" + }, + "dimensions": { + "type": "object", + "properties": { + "width": { + "type": "number" + }, + "height": { + "type": "number" + } + }, + "required": [ + "height", + "width" + ] + } + }, + "required": [ + "dimensions", + "label", + "link", + "src" + ] + } + }, + "required": [ + "aboutThisLink", + "logo", + "sponsorName" + ] + }, + "BrandingType": { + "anyOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "paid-content" + } + }, + "required": [ + "name" + ] + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "foundation" + } + }, + "required": [ + "name" + ] + }, + { + "type": "object", + "properties": { + "name": { + "type": "string", + "const": "sponsored" + } + }, + "required": [ + "name" + ] + } + ] + }, + "MainMedia": { + "anyOf": [ + { + "$ref": "#/definitions/YoutubeVideo", + "description": "For displaying embedded, playable videos directly in cards" + }, + { + "$ref": "#/definitions/SelfHostedVideo" + }, + { + "$ref": "#/definitions/Audio" + }, + { + "$ref": "#/definitions/Gallery" + } + ] + }, + "YoutubeVideo": { + "description": "For displaying embedded, playable videos directly in cards", + "allOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "Audio", + "Gallery", + "SelfHostedVideo", + "YoutubeVideo" + ], + "type": "string" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "YoutubeVideo" + }, + "id": { + "type": "string" + }, + "videoId": { + "type": "string" + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "origin": { + "type": "string" + }, + "title": { + "type": "string" + }, + "duration": { + "type": "number" + }, + "expired": { + "type": "boolean" + }, + "image": { + "type": "string" + } + }, + "required": [ + "duration", + "expired", + "height", + "id", + "origin", + "title", + "type", + "videoId", + "width" + ] + } + ] + }, + "SelfHostedVideo": { + "allOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "Audio", + "Gallery", + "SelfHostedVideo", + "YoutubeVideo" + ], + "type": "string" + } + }, + "required": [ + "type" + ] + }, + { + "type": "object", + "properties": { + "type": { + "type": "string", + "const": "SelfHostedVideo" + }, + "videoStyle": { + "$ref": "#/definitions/VideoPlayerFormat" + }, + "atomId": { + "type": "string" + }, + "sources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "src": { + "type": "string" + }, + "mimeType": { + "$ref": "#/definitions/SupportedVideoFileType" + } + }, + "required": [ + "mimeType", + "src" + ] + } + }, + "height": { + "type": "number" + }, + "width": { + "type": "number" + }, + "duration": { + "type": "number" + }, + "subtitleSource": { + "type": "string" + }, + "image": { + "type": "string" + } + }, + "required": [ + "atomId", + "duration", + "height", + "sources", + "type", + "videoStyle", + "width" + ] + } + ] }, - "encodedUrl": { + "SupportedVideoFileType": { + "enum": [ + "application/vnd.apple.mpegurl", + "application/x-mpegURL", + "video/mp4" + ], "type": "string" }, - "campaign": { - "type": "object", - "properties": { - "id": { - "type": "string" - }, - "name": { - "type": "string" - }, - "owner": { - "type": "string" + "Audio": { + "allOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "Audio", + "Gallery", + "SelfHostedVideo", + "YoutubeVideo" + ], + "type": "string" + } + }, + "required": [ + "type" + ] }, - "logo": { + { "type": "object", "properties": { - "src": { + "type": { + "type": "string", + "const": "Audio" + }, + "duration": { "type": "string" }, - "dimensions": { + "podcastImage": { "type": "object", "properties": { - "width": { - "type": "number" + "src": { + "type": "string" }, - "height": { - "type": "number" + "altText": { + "type": "string" } - }, - "required": [ - "height", - "width" - ] - }, - "link": { + } + } + }, + "required": [ + "duration", + "type" + ] + } + ] + }, + "Gallery": { + "allOf": [ + { + "type": "object", + "properties": { + "type": { + "enum": [ + "Audio", + "Gallery", + "SelfHostedVideo", + "YoutubeVideo" + ], "type": "string" } }, "required": [ - "dimensions", - "link", - "src" + "type" ] }, - "fontColour": { + { "type": "object", "properties": { - "hexCode": { + "type": { + "type": "string", + "const": "Gallery" + }, + "count": { "type": "string" } }, "required": [ - "hexCode" + "count", + "type" ] } - }, - "required": [ - "fontColour", - "id", - "logo", - "name", - "owner" ] }, - "title": { - "type": "string" - }, - "mainImageUrl": { + "OnwardsSource": { + "enum": [ + "curated-content", + "more-galleries", + "more-media-in-section", + "more-on-this-story", + "newsletters-page", + "related-content", + "related-stories", + "series", + "unknown-source" + ], "type": "string" }, - "thumbnailUrl": { - "type": "string" + "CommercialProperties": { + "type": "object", + "properties": { + "UK": { + "$ref": "#/definitions/EditionCommercialProperties" + }, + "US": { + "$ref": "#/definitions/EditionCommercialProperties" + }, + "AU": { + "$ref": "#/definitions/EditionCommercialProperties" + }, + "INT": { + "$ref": "#/definitions/EditionCommercialProperties" + }, + "EUR": { + "$ref": "#/definitions/EditionCommercialProperties" + } + }, + "required": [ + "AU", + "EUR", + "INT", + "UK", + "US" + ] }, - "standfirst": { - "type": "string" + "EditionCommercialProperties": { + "type": "object", + "properties": { + "adTargeting": { + "type": "array", + "items": { + "$ref": "#/definitions/AdTargetParam" + } + }, + "branding": { + "$ref": "#/definitions/Branding" + } + }, + "required": [ + "adTargeting" + ] }, - "cta": { + "AdTargetParam": { "type": "object", "properties": { - "url": { + "name": { "type": "string" }, - "image": { + "value": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "string" + } + ] + } + }, + "required": [ + "name", + "value" + ] + }, + "FEArticleBadgeType": { + "type": "object", + "properties": { + "seriesTag": { "type": "string" }, - "label": { + "imageUrl": { "type": "string" }, - "trackingCode": { + "enhanced": { + "$ref": "#/definitions/DCRBadgeType" + } + }, + "required": [ + "imageUrl", + "seriesTag" + ] + }, + "DCRBadgeType": { + "type": "object", + "properties": { + "imageSrc": { "type": "string" }, - "btnText": { + "href": { + "description": "Link to an external sponsor page", "type": "string" } }, "required": [ - "url" + "href", + "imageSrc" ] }, - "name": { - "type": "string" - }, - "owner": { - "type": "string" - }, - "logo": { + "FENavType": { "type": "object", "properties": { - "src": { + "currentUrl": { "type": "string" }, - "dimensions": { + "pillars": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "otherLinks": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "brandExtensions": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } + }, + "currentNavLink": { + "$ref": "#/definitions/FELinkType" + }, + "currentNavLinkTitle": { + "type": "string" + }, + "currentPillarTitle": { + "type": "string" + }, + "subNavSections": { "type": "object", "properties": { - "width": { - "type": "number" + "parent": { + "$ref": "#/definitions/FELinkType" }, - "height": { - "type": "number" + "links": { + "type": "array", + "items": { + "$ref": "#/definitions/FELinkType" + } } }, "required": [ - "height", - "width" + "links" ] }, - "link": { - "type": "string" + "readerRevenueLinks": { + "$ref": "#/definitions/ReaderRevenuePositions" } }, "required": [ - "dimensions", - "link", - "src" + "brandExtensions", + "currentUrl", + "otherLinks", + "pillars", + "readerRevenueLinks" ] }, - "fontColour": { + "ReaderRevenuePositions": { "type": "object", "properties": { - "hexCode": { - "type": "string" + "header": { + "$ref": "#/definitions/ReaderRevenueCategories" + }, + "footer": { + "$ref": "#/definitions/ReaderRevenueCategories" + }, + "sideMenu": { + "$ref": "#/definitions/ReaderRevenueCategories" + }, + "ampHeader": { + "$ref": "#/definitions/ReaderRevenueCategories" + }, + "ampFooter": { + "$ref": "#/definitions/ReaderRevenueCategories" } }, "required": [ - "hexCode" + "ampFooter", + "ampHeader", + "footer", + "header", + "sideMenu" ] }, - "body": { - "type": "string" - }, - "mainPicture": { - "type": "string" - }, - "mainPictureCaption": { - "type": "string" - }, - "video": { + "ReaderRevenueCategories": { "type": "object", "properties": { - "mediaId": { + "contribute": { "type": "string" }, - "title": { + "subscribe": { "type": "string" }, - "duration": { - "type": "number" - }, - "posterUrl": { + "support": { "type": "string" }, - "youtubeId": { + "supporter": { "type": "string" }, - "sources": { + "gifting": { + "type": "string" + } + }, + "required": [ + "contribute", + "subscribe", + "support", + "supporter" + ] + }, + "FooterType": { + "type": "object", + "properties": { + "footerLinks": { "type": "array", "items": { - "type": "object", - "properties": { - "format": { - "type": "string" - }, - "url": { - "type": "string" - }, - "rawFormat": { - "type": "string" - } - }, - "required": [ - "format", - "rawFormat", - "url" - ] + "type": "array", + "items": { + "$ref": "#/definitions/FooterLink" + } } } }, "required": [ - "duration", - "mediaId", - "posterUrl", - "sources", - "title" + "footerLinks" ] }, - "images": { - "type": "array", - "items": { - "type": "object", - "properties": { - "url": { - "type": "string" - }, - "width": { - "type": "number" - }, - "height": { - "type": "number" - }, - "title": { - "type": "string" - }, - "caption": { - "type": "string" - }, - "credit": { - "type": "string" - } + "FooterLink": { + "type": "object", + "properties": { + "text": { + "type": "string" }, - "required": [ - "caption", - "credit", - "title", - "url" - ] - } + "url": { + "type": "string" + }, + "dataLinkName": { + "type": "string" + }, + "extraClasses": { + "type": "string" + } + }, + "required": [ + "dataLinkName", + "text", + "url" + ] + }, + "MatchType": { + "description": "General", + "enum": [ + "CricketMatchType", + "FootballMatchType" + ], + "type": "string" } }, - "required": [ - "cta", - "encodedUrl", - "fontColour", - "id", - "images", - "logo", - "mainImageUrl", - "name", - "owner", - "standfirst", - "thumbnailUrl", - "title", - "url" - ], "$schema": "http://json-schema.org/draft-07/schema#" } \ No newline at end of file diff --git a/dotcom-rendering/src/frontend/schemas/feTagPage.json b/dotcom-rendering/src/frontend/schemas/feTagPage.json index 823e9285295..28cb0237b4b 100644 --- a/dotcom-rendering/src/frontend/schemas/feTagPage.json +++ b/dotcom-rendering/src/frontend/schemas/feTagPage.json @@ -1426,6 +1426,9 @@ "FeatureDesign", "FullPageInteractiveDesign", "GalleryDesign", + "HostedArticle", + "HostedGallery", + "HostedVideo", "InteractiveDesign", "InterviewDesign", "LetterDesign", diff --git a/dotcom-rendering/src/layouts/HostedArticleLayout.stories.tsx b/dotcom-rendering/src/layouts/HostedArticleLayout.stories.tsx index eb170d62a9d..5ec76fa500a 100644 --- a/dotcom-rendering/src/layouts/HostedArticleLayout.stories.tsx +++ b/dotcom-rendering/src/layouts/HostedArticleLayout.stories.tsx @@ -1,5 +1,7 @@ import type { Meta, StoryObj } from '@storybook/react-webpack5'; import { allModes } from '../../.storybook/modes'; +import { Labs as LabsFixture } from '../../fixtures/generated/fe-articles/Labs'; +import { enhanceArticleType } from '../types/article'; import { HostedArticleLayout } from './HostedArticleLayout'; const meta = { @@ -20,6 +22,7 @@ type Story = StoryObj; export const Apps = { args: { + content: enhanceArticleType(LabsFixture, 'Apps'), renderingTarget: 'Apps', }, parameters: { @@ -31,6 +34,7 @@ export const Apps = { export const Web = { args: { + content: enhanceArticleType(LabsFixture, 'Web'), renderingTarget: 'Web', }, parameters: { diff --git a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx index 0c8e0960165..a358a1d0a5e 100644 --- a/dotcom-rendering/src/layouts/HostedArticleLayout.tsx +++ b/dotcom-rendering/src/layouts/HostedArticleLayout.tsx @@ -1,9 +1,11 @@ import { css } from '@emotion/react'; import { grid } from '../grid'; +import type { HostedContent } from '../types/hostedContent'; import type { RenderingTarget } from '../types/renderingTarget'; interface Props { renderingTarget: RenderingTarget; + content: HostedContent; } interface WebProps extends Props { @@ -19,16 +21,24 @@ const border = css` `; export const HostedArticleLayout = (props: WebProps | AppProps) => { + const { + content: { + frontendData: { headline, standfirst }, + }, + renderingTarget, + } = props; + return ( <> - {props.renderingTarget === 'Web' ? 'Masthead' : null} + {renderingTarget === 'Web' ? 'Masthead' : null}
Main media
- Headline + {/** @todo Use ArticleHeadline component */} + {headline}
@@ -39,7 +49,7 @@ export const HostedArticleLayout = (props: WebProps | AppProps) => { Onward content
- Standfirst + {standfirst}
Meta
Body
diff --git a/dotcom-rendering/src/lib/articleFormat.ts b/dotcom-rendering/src/lib/articleFormat.ts index e5737e99adf..d6d958f82ea 100644 --- a/dotcom-rendering/src/lib/articleFormat.ts +++ b/dotcom-rendering/src/lib/articleFormat.ts @@ -29,6 +29,9 @@ export enum ArticleDesign { Timeline, Profile, Crossword, + HostedArticle, + HostedVideo, + HostedGallery, } export enum ArticleDisplay { @@ -118,6 +121,12 @@ export const decideDesign = ({ design }: Partial): ArticleDesign => { return ArticleDesign.Profile; case 'CrosswordDesign': return ArticleDesign.Crossword; + case 'HostedArticle': + return ArticleDesign.HostedArticle; + case 'HostedVideo': + return ArticleDesign.HostedVideo; + case 'HostedGallery': + return ArticleDesign.HostedGallery; default: return ArticleDesign.Standard; } diff --git a/dotcom-rendering/src/server/handler.hostedContent.apps.ts b/dotcom-rendering/src/server/handler.hostedContent.apps.ts index 5d4b474bb36..c3408776574 100644 --- a/dotcom-rendering/src/server/handler.hostedContent.apps.ts +++ b/dotcom-rendering/src/server/handler.hostedContent.apps.ts @@ -1,12 +1,12 @@ import type { RequestHandler } from 'express'; import { validateAsFEHostedContent } from '../model/validate'; -import { enhanceHostedContentType } from '../types/hostedContent'; +import { enhanceHostedContent } from '../types/hostedContent'; import { makePrefetchHeader } from './lib/header'; import { renderHtml } from './render.hostedContent.web'; export const handleAppsHostedContent: RequestHandler = ({ body }, res) => { const frontendData = validateAsFEHostedContent(body); - const hostedContent = enhanceHostedContentType(frontendData); + const hostedContent = enhanceHostedContent(frontendData); const { html, prefetchScripts } = renderHtml({ hostedContent, }); diff --git a/dotcom-rendering/src/server/handler.hostedContent.web.ts b/dotcom-rendering/src/server/handler.hostedContent.web.ts index 36a36fc02cc..2547adb0501 100644 --- a/dotcom-rendering/src/server/handler.hostedContent.web.ts +++ b/dotcom-rendering/src/server/handler.hostedContent.web.ts @@ -1,12 +1,12 @@ import type { RequestHandler } from 'express'; import { validateAsFEHostedContent } from '../model/validate'; -import { enhanceHostedContentType } from '../types/hostedContent'; +import { enhanceHostedContent } from '../types/hostedContent'; import { makePrefetchHeader } from './lib/header'; import { renderHtml } from './render.hostedContent.web'; export const handleHostedContent: RequestHandler = ({ body }, res) => { const frontendData = validateAsFEHostedContent(body); - const hostedContent = enhanceHostedContentType(frontendData); + const hostedContent = enhanceHostedContent(frontendData); const { html, prefetchScripts } = renderHtml({ hostedContent, }); diff --git a/dotcom-rendering/src/server/render.hostedContent.web.tsx b/dotcom-rendering/src/server/render.hostedContent.web.tsx index 81f76414bad..8e81eeda9f1 100644 --- a/dotcom-rendering/src/server/render.hostedContent.web.tsx +++ b/dotcom-rendering/src/server/render.hostedContent.web.tsx @@ -1,9 +1,17 @@ import { isString } from '@guardian/libs'; -import { HostedArticleLayout } from '../layouts/HostedArticleLayout'; -import { HostedGalleryLayout } from '../layouts/HostedGalleryLayout'; -import { getModulesBuild, getPathFromManifest } from '../lib/assets'; +import { ConfigProvider } from '../components/ConfigContext'; +import { HostedContentPage } from '../components/HostedContentPage'; +import { getArticleThemeString } from '../lib/articleFormat'; +import { + ASSET_ORIGIN, + generateScriptTags, + getModulesBuild, + getPathFromManifest, +} from '../lib/assets'; import { renderToStringWithEmotion } from '../lib/emotion'; import { polyfillIO } from '../lib/polyfill.io'; +import { createGuardian } from '../model/guardian'; +import type { Config } from '../types/configContext'; import type { HostedContent } from '../types/hostedContent'; import { htmlPageTemplate } from './htmlPageTemplate'; @@ -12,44 +20,102 @@ type Props = { }; export const renderHtml = ({ hostedContent }: Props) => { - const { type, frontendData } = hostedContent; + const { frontendData, theme } = hostedContent; - const title = `Advertiser content hosted by the Guardian: ${frontendData.title} | The Guardian`; + const title = `Advertiser content hosted by the Guardian: ${frontendData.webTitle} | The Guardian`; - const HostedLayout = - type === 'gallery' ? HostedGalleryLayout : HostedArticleLayout; const renderingTarget = 'Web'; + const config: Config = { + renderingTarget, + darkModeAvailable: + frontendData.config.abTests.darkModeWebVariant === 'variant', + assetOrigin: ASSET_ORIGIN, + editionId: frontendData.editionId, + }; const { html, extractedCss } = renderToStringWithEmotion( - , + + + , ); - // We don't send A/B tests or switches from frontend yet- do we need to? const build = getModulesBuild({ - tests: {}, - switches: {}, + tests: frontendData.config.abTests, + switches: frontendData.config.switches, }); + /** + * The highest priority scripts. + * These scripts have a considerable impact on site performance. + * Only scripts critical to application execution may go in here. + * Please talk to the dotcom platform team before adding more. + * Scripts will be executed in the order they appear in this array + */ const prefetchScripts = [ polyfillIO, getPathFromManifest(build, 'frameworks.js'), getPathFromManifest(build, 'index.js'), ].filter(isString); - // We currently don't send any of the data required for page config or window.guardian setup from frontend + const scriptTags = generateScriptTags(prefetchScripts); + + /** + * We escape windowGuardian here to prevent errors when the data + * is placed in a script tag on the page + */ + const guardian = createGuardian({ + editionId: frontendData.editionId, + stage: frontendData.config.stage, + frontendAssetsFullURL: frontendData.config.frontendAssetsFullURL, + revisionNumber: frontendData.config.revisionNumber, + sentryPublicApiKey: frontendData.config.sentryPublicApiKey, + sentryHost: frontendData.config.sentryHost, + keywordIds: frontendData.config.keywordIds, + dfpAccountId: frontendData.config.dfpAccountId, + adUnit: frontendData.config.adUnit, + ajaxUrl: frontendData.config.ajaxUrl, + googletagUrl: frontendData.config.googletagUrl, + switches: frontendData.config.switches, + abTests: frontendData.config.abTests, + serverSideABTests: frontendData.config.serverSideABTests, + brazeApiKey: frontendData.config.brazeApiKey, + isPaidContent: frontendData.pageType.isPaidContent, + contentType: frontendData.contentType, + shouldHideReaderRevenue: true, + googleRecaptchaSiteKey: frontendData.config.googleRecaptchaSiteKey, + // Until we understand exactly what config we need to make available client-side, + // add everything we haven't explicitly typed as unknown config + unknownConfig: frontendData.config, + }); + + const { linkedData, openGraphData, canonicalUrl } = frontendData; + const maybeArticleThemeString = getArticleThemeString(theme); + + /** + * @todo Create a separate hosted content page template + */ const pageHtml = htmlPageTemplate({ - scriptTags: [], + linkedData, + scriptTags, css: extractedCss, html, title, - description: frontendData.standfirst, - // @ts-expect-error no config data - guardian: {}, - canonicalUrl: '', + description: frontendData.trailText, + guardian, + openGraphData, + section: frontendData.config.section, + canonicalUrl, renderingTarget: 'Web', - // @ts-expect-error no config data - config: {}, - weAreHiring: false, + weAreHiring: !!frontendData.config.switches.weAreHiring, + config, + dataAttributes: { + ...(maybeArticleThemeString && { + 'article-theme': maybeArticleThemeString, + }), + }, }); return { html: pageHtml, prefetchScripts }; diff --git a/dotcom-rendering/src/types/hostedContent.ts b/dotcom-rendering/src/types/hostedContent.ts index 8f9704d26c5..4bb13ad19a4 100644 --- a/dotcom-rendering/src/types/hostedContent.ts +++ b/dotcom-rendering/src/types/hostedContent.ts @@ -1,25 +1,69 @@ import type { FEHostedContent } from '../frontend/feHostedContent'; +import { + ArticleDesign, + ArticleDisplay, + ArticleSpecial, +} from '../lib/articleFormat'; +import { enhanceMainMedia } from '../model/enhanceBlocks'; +import { enhanceCommercialProperties } from '../model/enhanceCommercialProperties'; +import { enhanceStandfirst } from '../model/enhanceStandfirst'; +import type { Article } from './article'; -type HostedContentType = 'article' | 'video' | 'gallery'; +export type HostedContent = Article; -export type HostedContent = { - frontendData: FEHostedContent; - type: HostedContentType; -}; +export const enhanceHostedContent = (data: FEHostedContent): HostedContent => { + // Temporarily hard coded + const format = { + display: ArticleDisplay.Standard, + design: ArticleDesign.HostedArticle, + theme: ArticleSpecial.Labs, + }; + + const serverTime = Date.now(); -export const enhanceHostedContentType = ( - data: FEHostedContent, -): HostedContent => { - let type: HostedContentType = 'article'; + /** @todo implement blocks */ + // const enhancedBlocks = enhanceBlocks(data.blocks, format, { + // renderingTarget, + // promotedNewsletter: data.promotedNewsletter, + // imagesForLightbox: [], + // hasAffiliateLinksDisclaimer: !!data.affiliateLinksDisclaimer, + // audioArticleImage: data.audioArticleImage, + // tags: data.tags, + // shouldHideAds: data.shouldHideAds, + // pageId: data.pageId, + // }); - if (data.video) { - type = 'video'; - } else if (data.images.length) { - type = 'gallery'; - } + const mainMediaElements = enhanceMainMedia( + format, + [], //imagesForLightbox + true, + data.main, + )(data.mainMediaElements); + /** @ts-expect-error -- @todo fix this! */ return { - frontendData: data, - type, + design: format.design, + display: format.display, + theme: format.theme, + serverTime, + storyPackage: undefined, + frontendData: { + ...data, + beaconURL: '', + mainMediaElements, + blocks: [], + standfirst: enhanceStandfirst(data.standfirst), + commercialProperties: enhanceCommercialProperties( + data.commercialProperties, + ), + /** + * This function needs to run at a higher level to most other enhancers + * because it needs both mainMediaElements and blocks in scope + * @todo implement for Hosted Content pages + */ + imagesForLightbox: [], + /** @todo implement for Hosted Content pages */ + imagesForAppsLightbox: [], + }, }; };