diff --git a/.eslintrc.js b/.eslintrc.js index 6f44c8b18f3..3017f94a396 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -11,7 +11,6 @@ module.exports = { // window.guardian is our global config/settings object 'id-denylist': ['error', 'guardian'], }, - ignorePatterns: ['javascripts.flow.archive'], overrides: [ { files: ['*.ts', '*.tsx'], @@ -35,13 +34,13 @@ module.exports = { ], }, }, - { - files: ['*.spec.ts'], - rules: { - // This rule erroneously flags up instances where you expect(obj.fn).toHaveBeenCalled - // Enabled for test files only - '@typescript-eslint/unbound-method': 'off', - }, - }, + { + files: ['*.spec.ts'], + rules: { + // This rule erroneously flags up instances where you expect(obj.fn).toHaveBeenCalled + // Enabled for test files only + '@typescript-eslint/unbound-method': 'off', + }, + }, ], }; diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 25083f88586..632b76009ce 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -6,8 +6,7 @@ "recommendations": [ "dbaeumer.vscode-eslint", "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "flowtype.flow-for-vscode" + "esbenp.prettier-vscode" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [ diff --git a/docs/01-start-here/04-troubleshooting.md b/docs/01-start-here/04-troubleshooting.md index e3687dbfa60..dc0a1e12cd5 100644 --- a/docs/01-start-here/04-troubleshooting.md +++ b/docs/01-start-here/04-troubleshooting.md @@ -30,7 +30,7 @@ If this doesn't work, you can clean everything with `cleanAll` in `root`. If you're still seeing errors, try clearing out all build and `.gitignore`d folders, which includes `target` folders: -> **Note:** This will wipe *everything*, not just `target/` (built) folders - including `node_modules/` +> **Note:** This will wipe *everything*, not just `target/` (built) folders - including `node_modules/` ``` git clean -fxd @@ -67,17 +67,6 @@ Run `make reinstall` to resolve. ### Accidentally ran `npm install` or `yarn install` Run `make reinstall` to resolve. -### Run Flowtype checks takes forever -The Flowtype checks happen automatically when you push your branch, assuming you have made JavaScript changes. - -Flow can sometimes take a long time to run. The first time you run Flowtype checks, Flow starts up a Flow server which is a slow process. If you think Flow is hanging ([a known bug](https://github.com/facebook/flow/issues/3528)), you can try stopping the Flow server by running: - -```bash -$ yarn flow stop -``` - -Next time you push your branch or manually run the Flow checks, a new Flow server will be started. - ### Global install permissions errors The script installs global npm packages without sudo. If you get npm permission errors, follow the guide to using npm without sudo [here](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md). diff --git a/docs/01-start-here/05-development-tips.md b/docs/01-start-here/05-development-tips.md index bfdcd60e3f9..64413a92c3d 100644 --- a/docs/01-start-here/05-development-tips.md +++ b/docs/01-start-here/05-development-tips.md @@ -24,10 +24,9 @@ make test make fix make validate ``` -These will fix up the linting issues and check all the flow types to make sure you won't have any issue -trying to push or with the simple parts of the build. +These will fix the linting issues to make sure you won't have any issue trying to push or with the simple parts of the build. -If you have already committed you can use `make fix-commits` to verify & fix your commited code. It's +If you have already committed you can use `make fix-commits` to verify & fix your commited code. It's faster than `make fix` but you will need to amend your previous commits to get a clean history. If you are wondering what other options make has, you can simply type `make` at the comment line. @@ -53,16 +52,16 @@ Ensure the Transport is Socket, the Debugger mode is Attach, and the port is set Start a new Debug session, and your breakpoints should be active. ### Developing in IntelliJ - + To use the sbt shell, you should use the same configuration for the JVM as in the [custom sbt script](../../sbt). -As an example of how to achieve this, the picture below demonstrates increasing the maximum heap size to 8000 and +As an example of how to achieve this, the picture below demonstrates increasing the maximum heap size to 8000 and providing the `APP_SECRET` as a Java system property. ![sbt_options](https://user-images.githubusercontent.com/4085817/67011346-4ce99980-f0e7-11e9-81fd-f1208e672800.png) Being able to use sbt shell has a number of advantages: - IntelliJ can be [configured to use sbt shell for build and import](https://intellij-support.jetbrains.com/hc/en-us/community/posts/115000117230-Sbt-shell-for-build-an-import); -- and (perhaps more pertinently), by clicking on the debug icon (pictured below) you can debug the Scala application(s) +- and (perhaps more pertinently), by clicking on the debug icon (pictured below) you can debug the Scala application(s) without having to configure the debugger yourself: ![debug_icon](https://user-images.githubusercontent.com/4085817/67011976-7bb43f80-f0e8-11e9-93fd-052ede190e34.png) diff --git a/static/src/javascripts.flow.archive/__flow__/stubs/raw.js b/static/src/javascripts.flow.archive/__flow__/stubs/raw.js deleted file mode 100644 index 6b568bdd545..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/stubs/raw.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/stubs/raw.js - * to .ts, then delete it. - */ - -export default ''; diff --git a/static/src/javascripts.flow.archive/__flow__/stubs/svg.js b/static/src/javascripts.flow.archive/__flow__/stubs/svg.js deleted file mode 100644 index c1cb56eb831..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/stubs/svg.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/stubs/svg.js - * to .ts, then delete it. - */ - -export default { - markup: '', -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/ab-tests.js b/static/src/javascripts.flow.archive/__flow__/types/ab-tests.js deleted file mode 100644 index cdf7824ae39..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/ab-tests.js +++ /dev/null @@ -1,190 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/ab-tests.js - * to .ts, then delete it. - */ - -import type { ReminderFields } from 'common/modules/commercial/templates/acquisitions-epic-reminder'; -import type { TickerSettings } from 'common/modules/commercial/ticker'; - -type ListenerFunction = (f: () => void) => void; - -declare type EpicCta = { url: string, ctaText: string }; - -declare type EpicTemplate = ( - EpicVariant, - AcquisitionsEpicTemplateCopy -) => string; - -declare type Variant = { - id: string, - test: (x: Object) => void, - campaignCode?: string, - canRun?: () => boolean, - impression?: ListenerFunction, - success?: ListenerFunction, - engagementBannerParams?: EngagementBannerTestParams, -}; - -declare type EpicVariant = Variant & { - // filters, where empty is taken to mean 'all', multiple entries are combined with OR - countryGroups: string[], - tagIds: string[], - sections: string[], - excludedTagIds: string[], - excludedSections: string[], - - supportURL: string, - componentName: string, - template: EpicTemplate, - classNames: string[], - showTicker?: boolean, // Deprecated, use tickerSettings instead - tickerSettings?: TickerSettings | null, - showReminderFields?: ReminderFields | null, - - buttonTemplate?: ( - primaryCta: EpicCta, - secondaryCta?: EpicCta, - reminderCta?: ReminderFields - ) => string, - ctaText?: string, - secondaryCta?: EpicCta, - copy: AcquisitionsEpicTemplateCopy, - backgroundImageUrl?: string, -}; - -declare type ABTest = { - id: string, - start: string, - expiry: string, - author: string, - description: string, - audience: number, - audienceOffset: number, - successMeasure: string, - audienceCriteria: string, - showForSensitive: boolean, - idealOutcome?: string, - dataLinkNames?: string, - ophanComponentId?: string, - variants: $ReadOnlyArray, - canRun: () => boolean, - notInTest?: () => void, -}; - -declare type Runnable = T & { - variantToRun: Variant, -}; - -declare type AcquisitionsABTest = ABTest & { - campaignId: string, - componentType: OphanComponentType, - geolocation: ?string, -}; - -declare type MaxViews = { - days: number, - count: number, - minDaysBetweenViews: number, -}; - -declare type ArticlesViewedSettings = { - minViews?: number, - maxViews?: number, - count: number, -}; - -declare type DeploymentRules = 'AlwaysAsk' | MaxViews; - -declare type EpicABTest = AcquisitionsABTest & { - campaignPrefix: string, - useLocalViewLog: boolean, - userCohort: AcquisitionsComponentUserCohort, - pageCheck: (page: Object) => boolean, - useTargetingTool: boolean, - insertEvent: string, - viewEvent: string, - highPriority: boolean, - deploymentRules: DeploymentRules, -}; - -declare type InitEpicABTestVariant = { - id: string, - products: $ReadOnlyArray, - test?: (html: string, variant: EpicVariant, parentTest: EpicABTest) => void, - countryGroups?: string[], - tagIds?: string[], - sections?: string[], - excludedTagIds?: string[], - excludedSections?: string[], - buttonTemplate?: ( - primaryCta: EpicCta, - secondaryCta?: EpicCta, - reminderCta?: ReminderFields - ) => string, - ctaText?: string, - secondaryCta?: EpicCta, - copy: AcquisitionsEpicTemplateCopy, - classNames?: string[], - showTicker?: boolean, - tickerSettings?: TickerSettings | null, - showReminderFields?: ReminderFields | null, - supportBaseURL?: string, - backgroundImageUrl?: string, - canRun?: () => boolean, - template?: EpicTemplate, -}; - -declare type InitBannerABTestVariant = { - id: string, - products: $ReadOnlyArray, - engagementBannerParams: () => Promise, -}; - -declare type InitEpicABTest = { - id: string, - start: string, - expiry: string, - author: string, - description: string, - audience: number, - audienceOffset: number, - successMeasure: string, - audienceCriteria: string, - idealOutcome: string, - campaignId: string, - canRun?: () => boolean, - variants: $ReadOnlyArray, - - campaignPrefix?: string, - useLocalViewLog?: boolean, - useTargetingTool?: boolean, - userCohort?: AcquisitionsComponentUserCohort, - pageCheck?: (page: Object) => boolean, - template?: EpicTemplate, - deploymentRules?: DeploymentRules, - testHasCountryName?: boolean, - geolocation: ?string, - highPriority: boolean, - articlesViewedSettings?: ArticlesViewedSettings, -}; - -declare type Interaction = { - component: string, - value: string, -}; - -/** - * the structure stored in localStorage - */ -declare type Participations = { - [testId: string]: { - variant: string, - }, -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/acquisitions.js b/static/src/javascripts.flow.archive/__flow__/types/acquisitions.js deleted file mode 100644 index 722698aadfa..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/acquisitions.js +++ /dev/null @@ -1,84 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/acquisitions.js - * to .ts, then delete it. - */ - -declare type AcquisitionsEpicTestimonialCopy = { - text: string, - name: string -} - -declare type AcquisitionsEpicTemplateCopy = { - heading?: string, - paragraphs: Array, - highlightedText?: string, - testimonial?: AcquisitionsEpicTestimonialCopy, - footer?: Array, -}; - -declare type EngagementBannerTemplateParams = { - titles?: Array, - leadSentence?: string, - closingSentence?: string, - messageText: string, - mobileMessageText?: string, - ctaText: string, - buttonCaption: string, - linkUrl: string, - hasTicker: boolean, - tickerHeader?: string, - signInUrl?: string, - secondaryLinkUrl?: string, - secondaryLinkLabel?: string, - subsLinkUrl?: string, -}; - -/** - * AllExistingSupporters - all recurring, all one-offs in last 3 months - * AllNonSupporters - no recurring, no one-offs in last 3 months - * Everyone - * PostAskPauseSingleContributors - people who made a contribution more than 3 months ago - * - * Note - PostAskPauseSingleContributors is a subset of AllNonSupporters, so priority ordering of these tests is important - */ -declare type AcquisitionsComponentUserCohort = 'AllExistingSupporters' | 'AllNonSupporters' | 'Everyone' | 'PostAskPauseSingleContributors'; - -declare type EngagementBannerParams = EngagementBannerTemplateParams & { - campaignCode: string, - pageviewId: string, - products: OphanProduct[], - isHardcodedFallback: boolean, - template: (templateParams: EngagementBannerTemplateParams) => string, - minArticlesBeforeShowingBanner: number, - userCohort: AcquisitionsComponentUserCohort, - bannerModifierClass?: string, - abTest?: { - name: string, - variant: string - }, - bannerShownCallback?: () => void, -}; - -declare type EngagementBannerTestParams = { - titles?: Array, - leadSentence?: string, - messageText?: string, - ctaText?: string, - buttonCaption?: string, - linkUrl?: string, - hasTicker?: boolean, - tickerHeader?: string, - products?: OphanProduct[], - template?: (templateParams: EngagementBannerTemplateParams) => string, - bannerModifierClass?: string, - minArticlesBeforeShowingBanner?: number, - userCohort?: AcquisitionsComponentUserCohort, - bannerShownCallback?: () => void, -} diff --git a/static/src/javascripts.flow.archive/__flow__/types/crosswords.js b/static/src/javascripts.flow.archive/__flow__/types/crosswords.js deleted file mode 100644 index 7a6ccb44a9f..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/crosswords.js +++ /dev/null @@ -1,76 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/crosswords.js - * to .ts, then delete it. - */ - -type Direction = 'across' | 'down'; - -type Separator = '-' | ','; - -type Axis = 'x' | 'y'; - -type SeparatorDescription = { - direction: Direction, - separator: Separator, -}; - -type SeparatorMap = { - [key: string]: SeparatorDescription, -}; - -type SeparatorLocations = { - [separator: Separator]: Array, -} - -type Position = { - [axis: Axis]: number -}; - -type Cell = { - number: number | string, - isHighlighted: boolean, - isEditable: boolean, - isError: boolean, - isAnimating: boolean, - value: string, -}; - -type Grid = Array>; - -type Clue = { - id: string, - number: number | string, - humanNumber: number | string, - group: Array, - clue: string, - position: Position, - separatorLocations: SeparatorLocations, - direction: Direction, - length: number, - solution: string, -}; - -type GroupClue = { - id: string, - number: ?number | ?string, - length: number, - separatorLocations: SeparatorLocations, - direction: '', - clue: ?string, -} - -type CluesIntersect = { - across?: Clue, - down?: Clue, -}; - -type ClueMap = { - [key: string]: CluesIntersect, -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/discussion-comment.js b/static/src/javascripts.flow.archive/__flow__/types/discussion-comment.js deleted file mode 100644 index 1722613fb92..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/discussion-comment.js +++ /dev/null @@ -1,17 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/discussion-comment.js - * to .ts, then delete it. - */ - -declare type Comment = { - body: string, - id: string, - replyTo?: Object, -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/discussion-profile.js b/static/src/javascripts.flow.archive/__flow__/types/discussion-profile.js deleted file mode 100644 index 3ae69cbcc42..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/discussion-profile.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/discussion-profile.js - * to .ts, then delete it. - */ - -// model: https://github.com/guardian/discussion-api/blob/master/discussion-api/src/main/scala/com.gu.discussion.api/model/Profile.scala#L26 - -declare type DiscussionProfile = { - apiUrl: string, - avatar: string, - badge: Array<{ - name: string, - }>, - details: { - about: string, - age: string, - gender: string, - interests: string, - location: string, - realName: string, - webPage: string, - }, - displayName: string, - isStaff?: boolean, - privateFields: { - canPostComment: boolean, - hasCommented: boolean, - isPremoderated: boolean, - }, - secureAvatarUrl: string, - userId: string, - webUrl: string, -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/global.js b/static/src/javascripts.flow.archive/__flow__/types/global.js deleted file mode 100644 index 400edb4807a..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/global.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/global.js - * to .ts, then delete it. - */ - -declare var __webpack_public_path__: string; - -declare var twttr: { - widgets?: { - load?: (?Element) => void, - }, -}; - -// #? TODO: this type def conflates definitions for CommonJS require and Webpack's require -// When we replace Webpack's require with dynamic imports, we can remove this type def -// https://webpack.js.org/guides/code-splitting/#dynamic-imports -declare var require: { - (id: string): any, - ensure( - ids: Array, - callback?: { (require: typeof require): void }, - chunkName?: string - ): void, - resolve: (id: string) => string, - cache: any, - main: typeof module, -}; - -declare type TagAtrribute = { - name: string, - value: string, -}; - -declare type ThirdPartyTag = { - shouldRun: boolean, - url?: string, - name?: string, - onLoad?: () => any, - beforeLoad?: () => any, - useImage?: boolean, - attrs?: Array, - async?: boolean, - loaded?: boolean, - insertSnippet?: () => any, -}; - -declare var jsdom: { - reconfigure: (settings: {}) => any, -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/membership.js b/static/src/javascripts.flow.archive/__flow__/types/membership.js deleted file mode 100644 index 06e3a3ca7b7..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/membership.js +++ /dev/null @@ -1,52 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/membership.js - * to .ts, then delete it. - */ - -declare type StripeCard = { - last4: string, - type: string, - stripePublicKeyForUpdate: string -} - -//the type of the response returned by https://github.com/guardian/members-data-api/blob/b5b7eeb9eff00fbcdf07dce6e95d1eac58d9b5e0/membership-attribute-service/app/models/AccountDetails.scala#L11-L16 -declare type UserDetails = { - tier: string, - isPaidTier: boolean, - regNumber?: string, - joinDate: string, - optIn: boolean, - subscription: { - start: string, - end: string, - trialLength: number, - nextPaymentDate: string, - nextPaymentPrice: number, - paymentMethod: string, - renewalDate: string, - cancelledAt: boolean, - subscriberId: string, - plan: { - name: string, - amount: number, - interval: string, - currency: string - }, - payPalEmail?: string, - account?: { - accountName: string, - }, - card?: StripeCard, - account?: { - accountName: string - }, - }, - alertText?: string -} diff --git a/static/src/javascripts.flow.archive/__flow__/types/ophan.js b/static/src/javascripts.flow.archive/__flow__/types/ophan.js deleted file mode 100644 index a48bac1602f..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/ophan.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/ophan.js - * to .ts, then delete it. - */ - -/** - * an individual A/B test, structured for Ophan - */ -declare type OphanABEvent = { - variantName: string, - complete: string | boolean, - campaignCodes?: $ReadOnlyArray, -}; - -/** - * the actual payload we send to Ophan: an object of OphanABEvents with test IDs as keys - */ -declare type OphanABPayload = { - [testId: string]: OphanABEvent, -}; - -declare type OphanProduct = - | 'CONTRIBUTION' - | 'RECURRING_CONTRIBUTION' - | 'MEMBERSHIP_SUPPORTER' - | 'MEMBERSHIP_PATRON' - | 'MEMBERSHIP_PARTNER' - | 'DIGITAL_SUBSCRIPTION' - | 'PRINT_SUBSCRIPTION'; - -declare type OphanAction = - | 'INSERT' - | 'VIEW' - | 'EXPAND' - | 'LIKE' - | 'DISLIKE' - | 'SUBSCRIBE' - | 'ANSWER' - | 'VOTE' - | 'CLICK'; - -declare type OphanComponentType = - | 'READERS_QUESTIONS_ATOM' - | 'QANDA_ATOM' - | 'PROFILE_ATOM' - | 'GUIDE_ATOM' - | 'TIMELINE_ATOM' - | 'NEWSLETTER_SUBSCRIPTION' - | 'SURVEYS_QUESTIONS' - | 'ACQUISITIONS_EPIC' - | 'ACQUISITIONS_ENGAGEMENT_BANNER' - | 'ACQUISITIONS_THANK_YOU_EPIC' - | 'ACQUISITIONS_HEADER' - | 'ACQUISITIONS_FOOTER' - | 'ACQUISITIONS_INTERACTIVE_SLICE' - | 'ACQUISITIONS_NUGGET' - | 'ACQUISITIONS_STANDFIRST' - | 'ACQUISITIONS_THRASHER' - | 'ACQUISITIONS_EDITORIAL_LINK' - | 'ACQUISITIONS_SUBSCRIPTIONS_BANNER' - | 'ACQUISITIONS_OTHER' - | 'SIGN_IN_GATE' - | 'RETENTION_ENGAGEMENT_BANNER'; - -declare type OphanComponent = { - componentType: OphanComponentType, - id?: string, - products?: $ReadOnlyArray, - campaignCode?: string, - labels?: $ReadOnlyArray -}; - -declare type OphanComponentEvent = { - component: OphanComponent, - action: OphanAction, - value?: string, - id?: string, - abTest?: { - name: string, - variant: string - } -}; diff --git a/static/src/javascripts.flow.archive/__flow__/types/user-attributes.js b/static/src/javascripts.flow.archive/__flow__/types/user-attributes.js deleted file mode 100644 index d86e8dcf690..00000000000 --- a/static/src/javascripts.flow.archive/__flow__/types/user-attributes.js +++ /dev/null @@ -1,40 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/__flow__/types/user-attributes.js - * to .ts, then delete it. - */ - - -//the type of the response returned by https://members-data-api.theguardian.com/user-attributes/me/mma-monthlycontribution -declare type ContributorDetails = { - tier: string, - isPaidTier: boolean, - joinDate: string, - optIn: boolean, - subscription: { - paymentMethod: string, - payPalEmail?: string, - card?: StripeCard, - start: string, - end: string, - nextPaymentPrice: number, - nextPaymentDate: string, - renewalDate: string, - cancelledAt: boolean, - subscriberId: string, - trialLength: number, - plan: { - name: string, - amount: number, - currency: string, - interval: string - } - }, - alertText?: string -} diff --git a/static/src/javascripts.flow.archive/boot.js b/static/src/javascripts.flow.archive/boot.js deleted file mode 100644 index 6cc1c3e6f3c..00000000000 --- a/static/src/javascripts.flow.archive/boot.js +++ /dev/null @@ -1,158 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/boot.js - * to .ts, then delete it. - */ - -// @flow - -// es7 polyfills not provided by pollyfill.io -import 'core-js/modules/es7.object.get-own-property-descriptors'; - -import domready from 'domready'; -import { bootStandard } from 'bootstraps/standard/main'; -import config from 'lib/config'; -import { markTime } from 'lib/user-timing'; -import { captureOphanInfo } from 'lib/capture-ophan-info'; -import reportError from 'lib/report-error'; -import { cmp, onConsentChange } from '@guardian/consent-management-platform'; -import { getLocale } from '@guardian/libs'; -import { getCookie } from 'lib/cookies'; -import { trackPerformance } from 'common/modules/analytics/google'; - -// Let webpack know where to get files from -// __webpack_public_path__ is a special webpack variable -// https://webpack.js.org/guides/public-path/#set-value-on-the-fly -// eslint-disable-next-line camelcase,no-undef -__webpack_public_path__ = `${config.get('page.assetsPath')}javascripts/`; - -// Debug preact in DEV -if (process.env.NODE_ENV !== 'production') { - // eslint-disable-next-line no-unused-expressions - import(/* webpackChunkName: "preact-debug" */ 'preact/debug'); -} - -// kick off the app -const go = () => { - domready(async () => { - // 1. boot standard, always - markTime('standard boot'); - bootStandard(); - - // Start CMP - // CCPA and TCFv2 - const browserId: ?string = getCookie('bwid') || undefined; - const pageViewId: ?string = config.get('ophan.pageViewId'); - const pubData: { - browserId?: ?string, - platform?: ?string, - pageViewId?: ?string, - } = { - platform: 'next-gen', - browserId, - pageViewId, - }; - - // keep this in sync with CONSENT_TIMING in src/web/components/App.tsx in frontend - // mark: CONSENT_TIMING - let recordedConsentTime = false; - onConsentChange(() => { - if (!recordedConsentTime) { - recordedConsentTime = true; - cmp.willShowPrivacyMessage().then(willShow => { - trackPerformance( - 'consent', - 'acquired', - willShow ? 'new' : 'existing' - ); - }); - } - }); - - cmp.init({ pubData, country: await getLocale() }); - - // 2. once standard is done, next is commercial - if (process.env.NODE_ENV !== 'production') { - window.guardian.adBlockers.onDetect.push(isInUse => { - const needsMessage = - isInUse && window.console && window.console.warn; - const message = - 'Do you have an adblocker enabled? Commercial features might fail to run, or throw exceptions.'; - if (needsMessage) { - window.console.warn(message); - } - }); - } - - // Start downloading these ASAP - - // eslint-disable-next-line no-nested-ternary - const fetchCommercial = config.get('switches.commercial') - ? (markTime('commercial request'), - import(/* webpackChunkName: "commercial" */ 'bootstraps/commercial')) - : Promise.resolve({ bootCommercial: () => {} }); - - const fetchEnhanced = window.guardian.isEnhanced - ? (markTime('enhanced request'), - import(/* webpackChunkName: "enhanced" */ 'bootstraps/enhanced/main')) - : Promise.resolve({ bootEnhanced: () => {} }); - - Promise.all([ - fetchCommercial.then(({ bootCommercial }) => { - markTime('commercial boot'); - try { - return bootCommercial(); - } catch (err) { - /** - * report sync errors in bootCommercial to - * Sentry with the commercial feature tag - * */ - reportError( - err, - { - feature: 'commercial', - }, - false - ); - } - }), - fetchEnhanced.then(({ bootEnhanced }) => { - markTime('enhanced boot'); - try { - return bootEnhanced(); - } catch (err) { - /** - * report sync errors in bootEnhanced to - * Sentry with the enhanced feature tag - * */ - reportError( - err, - { - feature: 'enhanced', - }, - false - ); - } - }), - ]).then(() => { - if (document.readyState === 'complete') { - captureOphanInfo(); - } else { - window.addEventListener('load', captureOphanInfo); - } - }); - }); -}; - -// make sure we've patched the env before running the app -if (window.guardian.polyfilled) { - go(); -} else { - window.guardian.onPolyfilled = go; -} diff --git a/static/src/javascripts.flow.archive/bootstraps/admin.js b/static/src/javascripts.flow.archive/bootstraps/admin.js deleted file mode 100644 index aaa11c5cd71..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/admin.js +++ /dev/null @@ -1,35 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/admin.js - * to .ts, then delete it. - */ - -// @flow -import { init as initDrama } from 'admin/bootstraps/drama'; -import { initABTests } from 'admin/bootstraps/abtests'; -import { initRadiator } from 'admin/bootstraps/radiator'; -import domReady from 'domready'; - -domReady(() => { - switch (window.location.pathname) { - case '/analytics/abtests': - initABTests(); - break; - - case '/dev/switchboard': - initDrama(); - break; - - case '/radiator': - initRadiator(); - break; - - default: // do nothing - } -}); diff --git a/static/src/javascripts.flow.archive/bootstraps/atoms/snippet.js b/static/src/javascripts.flow.archive/bootstraps/atoms/snippet.js deleted file mode 100644 index e97313a666b..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/atoms/snippet.js +++ /dev/null @@ -1,56 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/atoms/snippet.js - * to .ts, then delete it. - */ - -// @flow - -import domready from 'domready'; -import config from 'lib/config'; -import fastdom from 'lib/fastdom-promise'; -import { comready } from 'lib/comready'; -import { send } from 'commercial/modules/messenger/send'; - -// let webpack know where to get files from -// __webpack_public_path__ is a special webpack variable -// https://webpack.js.org/guides/public-path/#set-value-on-the-fly -// eslint-disable-next-line camelcase,no-undef -__webpack_public_path__ = `${config.get('page.assetsPath')}javascripts/`; - -const updateHeight = () => { - fastdom - .measure( - () => - document.documentElement && - document.documentElement.getBoundingClientRect().height - ) - .then(height => { - send('resize', { height }); - }); -}; - -Promise.all([ - window.guardian.polyfilled - ? Promise.resolve() - : new Promise(resolve => { - window.guardian.onPolyfilled = resolve; - }), - new Promise(domready), - new Promise(comready), -]).then(() => { - updateHeight(); - Array.from(document.getElementsByTagName('details')) - .slice(0, 1) - .forEach(details => { - new MutationObserver(updateHeight).observe(details, { - attributes: true, - }); - }); -}); diff --git a/static/src/javascripts.flow.archive/bootstraps/atoms/storyquestions.js b/static/src/javascripts.flow.archive/bootstraps/atoms/storyquestions.js deleted file mode 100644 index 99e387e5ed9..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/atoms/storyquestions.js +++ /dev/null @@ -1,59 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/atoms/storyquestions.js - * to .ts, then delete it. - */ - -// @flow - -import domready from 'domready'; -import { comready } from 'lib/comready'; -import config from 'lib/config'; -import fastdom from 'lib/fastdom-promise'; -import { send } from 'commercial/modules/messenger/send'; - -// let webpack know where to get files from -// __webpack_public_path__ is a special webpack variable -// https://webpack.js.org/guides/public-path/#set-value-on-the-fly -// eslint-disable-next-line camelcase,no-undef -__webpack_public_path__ = `${config.get('page.assetsPath')}javascripts/`; - -const updateHeight = () => { - fastdom - .measure( - () => - document.documentElement && - document.documentElement.getBoundingClientRect().height - ) - .then(height => { - send('resize', { height }); - }); -}; - -Promise.all([ - window.guardian.polyfilled - ? Promise.resolve() - : new Promise(resolve => { - window.guardian.onPolyfilled = resolve; - }), - new Promise(domready), - new Promise(comready), -]).then(() => { - updateHeight(); - - // Brittle but will work - Array.from(document.getElementsByClassName('user__question')) - .slice(0, 1) - .forEach((sq: Element) => { - new MutationObserver(updateHeight).observe(sq, { - childList: true, - subtree: true, - }); - }); -}); diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/accessibility.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/accessibility.js deleted file mode 100644 index 8ccdcd0c290..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/accessibility.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/accessibility.js - * to .ts, then delete it. - */ - -// @flow -import React, { Component, render } from 'preact/compat'; - -import { saveState, isOn } from 'common/modules/accessibility/main'; - -const DOM_ID: string = 'js-accessibility-preferences'; - -type AccessibilityState = { - 'flashing-elements': boolean, -}; - -class BinaryToggle extends Component<*, *> { - render() { - return ( -
-
- -
-
- ); - } -} - -class Accessibility extends Component<*, *> { - constructor() { - super(); - this.state = ({ - 'flashing-elements': isOn('flashing-elements'), - }: AccessibilityState); - } - - toggle(key: string): void { - const newState = {}; - newState[key] = !this.state[key]; - this.setState(newState, function() { - saveState(this.state); - }); - } - - render(): Object { - return ( -
-
-

- We aim to make this site accessible to a wide audience - and to ensure a great experience for all users by - conforming to World Wide Web Consortium accessibility - guidelines (W3C's WCAG) -

-

- However, if you are having trouble reading this website - you can change the way it looks or disable some of its - functionalities. -

- - Allow flashing elements - , - this.state['flashing-elements'] - ? ' Untick this to disable flashing and moving elements' - : ' Tick this to enable flashing or moving elements.', - ]} - enabled={this.state['flashing-elements']} - handleChange={this.toggle.bind( - this, - 'flashing-elements' - )} - /> -
-
- ); - } -} - -const init = (callback: () => void): void => { - const el = document.getElementById(DOM_ID); - - if (el) { - render(, el, callback); - } -}; - -export { DOM_ID, init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/article-liveblog-common.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/article-liveblog-common.js deleted file mode 100644 index 533445ecfca..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/article-liveblog-common.js +++ /dev/null @@ -1,42 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/article-liveblog-common.js - * to .ts, then delete it. - */ - -// @flow -/** Bootstrap for functionality common to articles and live blogs */ -import fence from 'fence'; -import $ from 'lib/$'; -import { catchErrorsWithContext } from 'lib/robust'; -import { shouldHideFlashingElements } from 'common/modules/accessibility/helpers'; -import { init as initT, enhanceTweets } from 'common/modules/article/twitter'; -import { lastModified } from 'common/modules/ui/last-modified'; -import { init as selectionSharingInit } from 'common/modules/ui/selection-sharing'; - -const initFence = (): void => { - $('.fenced').each(fence.render); -}; - -const initTwitter = (): void => { - initT(); - enhanceTweets(); -}; - -const init = (): void => { - catchErrorsWithContext([ - ['trail-a11y', shouldHideFlashingElements], - ['trail-fence', initFence], - ['trail-twitter', initTwitter], - ['trail-sharing', selectionSharingInit], - ['trail-last-modified', lastModified], - ]); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/article-minute.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/article-minute.js deleted file mode 100644 index b9446610d3e..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/article-minute.js +++ /dev/null @@ -1,24 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/article-minute.js - * to .ts, then delete it. - */ - -// @flow -import { init as initLiveblogCommon } from 'bootstraps/enhanced/article-liveblog-common'; -import { initTrails } from 'bootstraps/enhanced/trail'; -import { init as fullHeight } from 'common/modules/ui/full-height'; - -const init = (): void => { - initLiveblogCommon(); - initTrails(); - fullHeight(); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/article.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/article.js deleted file mode 100644 index dc99a787449..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/article.js +++ /dev/null @@ -1,89 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/article.js - * to .ts, then delete it. - */ - -// @flow -/* eslint-disable no-new */ -import config from 'lib/config'; -import qwery from 'qwery'; -import $ from 'lib/$'; -import { catchErrorsWithContext } from 'lib/robust'; -import { isBreakpoint } from 'lib/detect'; -import mediator from 'lib/mediator'; -import { getUrlVars } from 'lib/url'; -import { - insertTagRichLink, - upgradeRichLinks, -} from 'common/modules/article/rich-links'; -import { upgradeMembershipEvents } from 'common/modules/article/membership-events'; -import { geoMostPopular } from 'common/modules/onward/geo-most-popular'; -import { handleCompletion as handleQuizCompletion } from 'common/modules/atoms/quiz'; -import { init as initLiveblogCommon } from 'bootstraps/enhanced/article-liveblog-common'; -import { initTrails } from 'bootstraps/enhanced/trail'; -import { initCampaign } from 'journalism/modules/render-campaign'; - -import ophan from 'ophan/ng'; - -const modules = { - initCmpParam() { - const allvars = getUrlVars(); - - if (allvars.CMP) { - $('.element-pass-cmp').each(el => { - el.src = `${el.src}?CMP=${allvars.CMP}`; - }); - } - }, - - initRightHandComponent() { - const mainColumn = qwery('.js-content-main-column'); - // only render when we have >1000px or more (enough space for ad + most popular) - if ( - !config.hasTone('Match reports') && - mainColumn[0] && - mainColumn[0].offsetHeight > 1150 && - isBreakpoint({ - min: 'desktop', - }) - ) { - geoMostPopular.render(); - } else { - mediator.emit('modules:onward:geo-most-popular:cancel'); - } - }, - - initQuizListeners() { - // This event is for older-style quizzes implemented as interactives. See https://github.com/guardian/quiz-builder - mediator.on('quiz/ophan-event', ophan.record); - }, - - emitReadyEvent() { - mediator.emit('page:article:ready'); - }, -}; - -const init = () => { - catchErrorsWithContext([ - ['article-trails', initTrails], - ['article-liveblog-common', initLiveblogCommon], - ['article-righthand-component', modules.initRightHandComponent], - ['article-cmp-param', modules.initCmpParam], - ['article-quiz-listeners', modules.initQuizListeners], - ['article-rich-links', upgradeRichLinks], - ['article-tag-rich-link', insertTagRichLink], - ['article-upgrade-membership-events', upgradeMembershipEvents], - ['article-mediator-emit-event', modules.emitReadyEvent], - ['article-handle-quiz-completion', handleQuizCompletion], - ['article-campaign', initCampaign], - ]); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/common.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/common.js deleted file mode 100644 index a8cefa40d6a..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/common.js +++ /dev/null @@ -1,355 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/common.js - * to .ts, then delete it. - */ - -// @flow -/* eslint-disable no-new */ -/* TODO - fix module constructors */ -import bean from 'bean'; -import config from 'lib/config'; -import { cleanUp, addSessionCookie } from 'lib/cookies'; -import mediator from 'lib/mediator'; -import { getUrlVars } from 'lib/url'; -import { catchErrorsWithContext } from 'lib/robust'; -import { storage } from '@guardian/libs'; -import { mediaListener } from 'common/modules/analytics/media-listener'; -import interactionTracking from 'common/modules/analytics/interaction-tracking'; -import { initAnalyticsRegister } from 'common/modules/analytics/register'; -import { ScrollDepth } from 'common/modules/analytics/scrollDepth'; -import { requestUserSegmentsFromId } from 'common/modules/commercial/user-ad-targeting'; -import { - refresh as refreshUserFeatures, - extendContribsCookieExpiry, -} from 'common/modules/commercial/user-features'; -import { initCommentCount } from 'common/modules/discussion/comment-count'; -import { init as initCookieRefresh } from 'common/modules/identity/cookierefresh'; -import { initNavigation } from 'common/modules/navigation/navigation'; -import { Profile } from 'common/modules/navigation/profile'; -import { Search } from 'common/modules/navigation/search'; -import { emailSignInBanner } from 'common/modules/identity/email-sign-in-banner/index'; -import { - initMembership, - membershipBanner, -} from 'common/modules/navigation/membership'; -import { - logHistory, - logSummary, - showInMegaNav, - incrementDailyArticleCount, - incrementWeeklyArticleCount, -} from 'common/modules/onward/history'; -import { initAccessibilityPreferences } from 'common/modules/ui/accessibility-prefs'; -import { initClickstream } from 'common/modules/ui/clickstream'; -import { init as initDropdowns } from 'common/modules/ui/dropdowns'; -import { fauxBlockLink } from 'common/modules/ui/faux-block-link'; -import { init as initRelativeDates } from 'common/modules/ui/relativedates'; -import { init as initTabs } from 'common/modules/ui/tabs'; -import { Toggles } from 'common/modules/ui/toggles'; -import { init as initIdentity } from 'bootstraps/enhanced/identity-common'; -import { init as initBannerPicker } from 'common/modules/ui/bannerPicker'; -import { trackConsentCookies } from 'common/modules/analytics/send-privacy-prefs'; -import { getAllAdConsentsWithState } from 'common/modules/commercial/ad-prefs.lib'; -import ophan from 'ophan/ng'; -import { adFreeBanner } from 'common/modules/commercial/ad-free-banner'; -import { init as initReaderRevenueDevUtils } from 'common/modules/commercial/reader-revenue-dev-utils'; -import { - cmpBannerCandidate, - addPrivacySettingsLink, -} from 'common/modules/ui/cmp-ui'; -import { signInGate } from 'common/modules/identity/sign-in-gate'; -import { brazeBanner } from 'commercial/modules/brazeBanner'; -import { readerRevenueBanner } from 'common/modules/commercial/reader-revenue-banner'; -import { getArticleCountConsent } from 'common/modules/commercial/contributions-service'; -import { init as initGoogleAnalytics } from 'common/modules/tracking/google-analytics'; - -const initialiseTopNavItems = (): void => { - const header: ?HTMLElement = document.getElementById('header'); - - new Search(); - - if (header) { - if (config.get('switches.idProfileNavigation')) { - const profile: Profile = new Profile({ - url: config.get('page.idUrl'), - }); - profile.init(); - } - } -}; - -const initialiseNavigation = (): void => { - initNavigation(); -}; - -const showTabs = (): void => { - ['modules:popular:loaded', 'modules:geomostpopular:ready'].forEach( - event => { - mediator.on(event, initTabs); - } - ); -}; - -const showToggles = (): void => { - const toggles: Toggles = new Toggles(); - toggles.init(); - toggles.reset(); - initDropdowns(); -}; - -const showRelativeDates = (): void => { - initRelativeDates(); -}; - -const initialiseClickstream = (): void => { - initClickstream({ - filter: ['a', 'button'], - }); -}; - -const loadAnalytics = (): void => { - interactionTracking.init(); - if (config.get('switches.ophan')) { - if (config.get('switches.scrollDepth')) { - mediator.on('scrolldepth:data', ophan.record); - - new ScrollDepth({ - isContent: /Article|LiveBlog/.test( - config.get('page.contentType') - ), - }); - } - } -}; - -const loadGoogleAnalytics = (): void => { - const handleGoogleAnalytics = (gaHasConsent: boolean): void => { - if (gaHasConsent && !config.get('page.gaIsInitalised')) { - window.guardian.googleAnalytics.initialiseGa() - } else { - // set window.ga back to a stub function when ga consents are removed so that we don't track events - window.ga = function() {} - config.set('page.gaIsInitalised', false) - } - } - mediator.on('ga:gaConsentChange', handleGoogleAnalytics) -} - -const cleanupCookies = (): void => { - cleanUp([ - 'mmcore.pd', - 'mmcore.srv', - 'mmid', - 'GU_ABFACIA', - 'GU_FACIA', - 'GU_ALPHA', - 'GU_ME', - 'at', - 'gu_join_date', - ]); -}; - -const cleanupLocalStorage = (): void => { - const deprecatedKeys = [ - 'gu.subscriber', - 'gu.contributor', - 'gu.cachedRecommendations', - 'gu.recommendationsEnabled', - 'gu.abb3.exempt', - ]; - deprecatedKeys.forEach(key => storage.local.remove(key)); -}; - -const updateHistory = (): void => { - const page = config.get('page'); - - if (page) { - const { contentType } = page; - - if (contentType !== 'Network Front') { - logSummary(page); - } - - logHistory(page); - } -}; - -const updateArticleCounts = async (): Promise => { - const page = config.get('page'); - const hasConsentedToArticleCounts = await getArticleCountConsent(); - - if (page && hasConsentedToArticleCounts) { - incrementDailyArticleCount(page); - incrementWeeklyArticleCount(page); - } -}; - -const showHistoryInMegaNav = (): void => { - if (config.get('switches.historyTags')) { - mediator.once('modules:nav:open', () => { - showInMegaNav(); - }); - } -}; - -const idCookieRefresh = (): void => { - if (config.get('switches.idCookieRefresh')) { - initCookieRefresh(); - } -}; - -const windowEventListeners = (): void => { - ['orientationchange'].forEach(event => { - window.addEventListener( - event, - mediator.emit.bind(mediator, `window:${event}`) - ); - }); -}; - -const checkIframe = (): void => { - if (window.self !== window.top) { - const html = document.documentElement; - if (html) { - html.classList.add('iframed'); - } - } -}; - -const normalise = (): void => { - if (document.location.hash === '#nfn') { - storage.local.set('nfn', true); - } - if (document.location.hash === '#nnfn') { - storage.local.remove('nfn'); - } - if (storage.local.get('nfn')) { - import('common/modules/ui/normalise').then(({ go }) => { - go(); - }); - } -}; - -const startRegister = (): void => { - initAnalyticsRegister(); -}; - -const initDiscussion = (): void => { - if (config.get('switches.enableDiscussionSwitch')) { - initCommentCount(); - } -}; - -const testCookie = (): void => { - const queryParams = getUrlVars(); - if (queryParams.test) { - addSessionCookie('GU_TEST', encodeURIComponent(queryParams.test)); - } -}; - -const initOpenOverlayOnClick = (): void => { - let offset: ?number; - const body = document.body; - - if (!body) return; - - bean.on(body, 'click', '[data-open-overlay-on-click]', e => { - const elId = (e.currentTarget: any).getAttribute( - 'data-open-overlay-on-click' - ); - offset = body.scrollTop; - body.classList.add('has-overlay'); - const el = document.getElementById(elId); - if (el) { - el.classList.add('overlay--open'); - body.appendChild(el); - } - }); - - bean.on(body, 'click', '.js-overlay-close', e => { - const overlay = (e.target: any).closest('.overlay'); - if (overlay) { - overlay.classList.remove('overlay--open'); - } - body.classList.remove('has-overlay'); - window.setTimeout(() => { - if (offset) { - body.scrollTop = offset; - offset = null; - } - }, 1); - }); -}; - -const initPublicApi = (): void => { - // BE CAREFUL what you expose here... - window.guardian.api = {}; -}; - -const initialiseBanner = (): void => { - // ordered by priority - const bannerList = [ - cmpBannerCandidate, - signInGate, - membershipBanner, - readerRevenueBanner, - adFreeBanner, - emailSignInBanner, - brazeBanner, - ]; - - initBannerPicker(bannerList); -}; - -const initialiseConsentCookieTracking = (): void => - trackConsentCookies(getAllAdConsentsWithState()); - -const init = (): void => { - catchErrorsWithContext([ - // Analytics comes at the top. If you think your thing is more important then please think again... - ['c-analytics', loadAnalytics], - ['c-consent-cookie-tracking', initialiseConsentCookieTracking], - ['c-identity', initIdentity], - ['c-adverts', requestUserSegmentsFromId], - ['c-discussion', initDiscussion], - ['c-test-cookie', testCookie], - ['c-event-listeners', windowEventListeners], - ['c-block-link', fauxBlockLink], - ['c-iframe', checkIframe], - ['c-normalise', normalise], - ['c-tabs', showTabs], - ['c-top-nav', initialiseTopNavItems], - ['c-init-nav', initialiseNavigation], - ['c-toggles', showToggles], - ['c-dates', showRelativeDates], - ['c-clickstream', initialiseClickstream], - ['c-history', updateHistory], - ['c-id-cookie-refresh', idCookieRefresh], - ['c-history-nav', showHistoryInMegaNav], - ['c-start-register', startRegister], - ['c-cookies', cleanupCookies], - ['c-extend-contribs-expiry', extendContribsCookieExpiry], - ['c-localStorage', cleanupLocalStorage], - ['c-overlay', initOpenOverlayOnClick], - ['c-public-api', initPublicApi], - ['c-media-listeners', mediaListener], - ['c-accessibility-prefs', initAccessibilityPreferences], - ['c-user-features', refreshUserFeatures], - ['c-membership', initMembership], - ['c-banner-picker', initialiseBanner], - ['c-increment-article-counts', updateArticleCounts], - ['c-reader-revenue-dev-utils', initReaderRevenueDevUtils], - ['c-add-privacy-settings-link', addPrivacySettingsLink], - ['c-load-google-analytics', loadGoogleAnalytics], - ['c-google-analytics', initGoogleAnalytics], - ]); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/crosswords.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/crosswords.js deleted file mode 100644 index 33abcf41673..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/crosswords.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/crosswords.js - * to .ts, then delete it. - */ - -// @flow -import { initCrosswords } from 'common/modules/crosswords/main'; -import { initCrosswordDiscussion } from 'common/modules/crosswords/comments'; -import { initSeries } from 'common/modules/crosswords/series'; - -export const init = (): void => { - initCrosswords(); - initCrosswordDiscussion(); - initSeries(); -}; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/facia.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/facia.js deleted file mode 100644 index 0c1a31102e5..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/facia.js +++ /dev/null @@ -1,127 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/facia.js - * to .ts, then delete it. - */ - -// @flow -import $ from 'lib/$'; -import config from 'lib/config'; -import { isBreakpoint } from 'lib/detect'; -import mediator from 'lib/mediator'; -import { catchErrorsWithContext } from 'lib/robust'; -import { shouldHideFlashingElements } from 'common/modules/accessibility/helpers'; -import stocks from 'common/modules/business/stocks'; -import { GeoMostPopularFront } from 'facia/modules/onwards/geo-most-popular-front'; -import { GeoMostPopularFrontExtended } from 'facia/modules/onwards/geo-most-popular-front-extended'; -import { ContainerToggle } from 'facia/modules/ui/container-toggle'; -import { init as initShowMore } from 'facia/modules/ui/container-show-more'; -import { lazyLoadContainers } from 'facia/modules/ui/lazy-load-containers'; -import { showUpdatesFromLiveBlog } from 'facia/modules/ui/live-blog-updates'; -import { init as initSnaps } from 'facia/modules/ui/snaps'; -import { Weather } from 'facia/modules/onwards/weather'; -import partial from 'lodash/partial'; -import { videoContainerInit } from 'common/modules/video/video-container'; -import { addContributionsBanner } from 'journalism/modules/audio-series-add-contributions'; - -const showSnaps = (): void => { - initSnaps(); - mediator.on('modules:container:rendered', initSnaps); -}; - -const showContainerShowMore = (): void => { - mediator.addListeners({ - 'modules:container:rendered': initShowMore, - 'page:front:ready': initShowMore, - }); -}; - -const showContainerToggle = (): void => { - const containerToggleAdd = context => { - $('.js-container--toggle', $(context || document)[0]).each( - container => { - const toggle = new ContainerToggle(container); - toggle.addToggle(); - } - ); - }; - mediator.addListeners({ - 'page:front:ready': containerToggleAdd, - 'modules:geomostpopular:ready': partial( - containerToggleAdd, - '.js-popular-trails' - ), - }); -}; - -const upgradeMostPopularToGeo = (): void => { - if (config.get('switches.geoMostPopular')) { - if (config.get('switches.extendedMostPopularFronts')) { - new GeoMostPopularFrontExtended().go(); - } else { - new GeoMostPopularFront().go(); - } - } -}; - -const showWeather = (): void => { - if (config.get('switches.weather')) { - mediator.on('page:front:ready', () => { - Weather.init(); - }); - } -}; - -const showLiveblogUpdates = (): void => { - if ( - isBreakpoint({ - min: 'desktop', - }) - ) { - mediator.on('page:front:ready', () => { - showUpdatesFromLiveBlog(); - }); - } -}; - -const upgradeVideoPlaylists = (): void => { - $('.js-video-playlist').each(el => { - videoContainerInit(el); - }); -}; - -const finished = (): void => { - mediator.emit('page:front:ready'); -}; - -const addContributionBannerToAudioSeries = (): void => { - const isFlagshipPage = $('#flagship-audio').length > 0; - if (isFlagshipPage) { - addContributionsBanner(); - } -}; - -const init = (): void => { - catchErrorsWithContext([ - ['f-accessibility', shouldHideFlashingElements], - ['f-snaps', showSnaps], - ['f-show-more', showContainerShowMore], - ['f-container-toggle', showContainerToggle], - ['f-geo-most-popular', upgradeMostPopularToGeo], - ['f-lazy-load-containers', lazyLoadContainers], - ['f-stocks', stocks], - ['f-weather', showWeather], - ['f-live-blog-updates', showLiveblogUpdates], - ['f-video-playlists', upgradeVideoPlaylists], - ['f-audio-flagship-contributions', addContributionBannerToAudioSeries], - ['f-finished', finished], - ]); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/football.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/football.js deleted file mode 100644 index 0d4b9d80b85..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/football.js +++ /dev/null @@ -1,385 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/football.js - * to .ts, then delete it. - */ - -// @flow -import bean from 'bean'; -import bonzo from 'bonzo'; -import $ from 'lib/$'; -import config from 'lib/config'; -import fetchJson from 'lib/fetch-json'; -import { - isCompetition, - isMatch, - isFootballStatsPage, - isLiveClockwatch, -} from 'lib/page'; -import reportError from 'lib/report-error'; -import { TableDoughnut } from 'common/modules/charts/table-doughnut'; -import { - statsFor, - tableFor, - matchDayFor, -} from 'common/modules/sport/football/football'; -import { MatchInfo } from 'common/modules/sport/football/match-info'; -import { MatchListLive } from 'common/modules/sport/football/match-list-live'; -import { tagPageStats } from 'common/modules/sport/football/tag-page-stats'; -import { ScoreBoard } from 'common/modules/sport/score-board'; -import { replaceLocaleTimestamps } from 'common/modules/ui/relativedates'; - -declare type Extra = { - content?: Element, - chart?: string, - importance?: number, - name?: string, - ready: boolean, -}; - -const renderNav = ( - match: Object, - callback?: (resp: Object, $nav: bonzo, endpoint: string) => void -): Promise => { - const matchInfo = new MatchInfo(match, config.get('page.pageId')); - - return matchInfo - .fetch() - .then( - (resp: Object): void => { - let $nav; - - if (resp.nav && resp.nav.trim().length > 0) { - $nav = $.create(resp.nav) - .first() - .each(nav => { - if (match.id || $('.tabs__tab', nav).length > 2) { - $('.js-sport-tabs').append(nav); - } - }); - } - - if (callback) { - callback(resp, $nav, matchInfo.endpoint); - } - } - ) - .catch(() => { - $('.score-container').remove(); - $('.js-score').removeClass('u-h'); - }); -}; - -const renderExtras = (_extras: Array): void => { - const extras = [..._extras].filter(extra => extra); - const ready = - extras.filter(extra => extra && extra.ready === false).length === 0; - - if (ready) { - if (config.get('page.isLiveBlog')) { - extras.filter(Boolean).forEach(extra => { - $('.js-live-blog__sticky-components').append(extra.content); - $('.football-possession').append(extra.chart); - }); - } else { - extras.filter(Boolean).forEach(extra => { - $('.js-after-article').append(extra.content); - $('.football-possession').append(extra.chart); - }); - } - } -}; - -const renderTable = (competition: string, extras: Array): void => { - extras[2] = { - ready: false, - }; - - $.create( - `
- ` - ).each(container => { - tableFor(competition) - .fetch(container) - .then(() => { - if ($('.table__container', container).length > 0) { - extras[2] = { - name: 'Table', - importance: 3, - content: container, - ready: true, - }; - } else { - extras[2] = undefined; - } - - renderExtras(extras); - }) - .catch(() => { - delete extras[2]; - renderExtras(extras); - }); - }); -}; - -const loading = ( - elem: HTMLElement, - message: string = 'Loading…', - link: { - text: string, - href: string, - } -): void => { - bonzo(elem).append( - bonzo.create(` -
-
${message}
- ${link.text} -
-
- `) - ); -}; - -const loaded = (elem: HTMLElement): void => { - $('.loading', elem).remove(); -}; - -const init = (): void => { - const extras = []; - - isMatch( - (match: Object): void => { - $('article').addClass('content--has-scores'); - - extras[0] = { - ready: false, - }; - if (match.pageType === 'stats') { - renderNav(match); - } else { - const $h = $('.js-score'); - const scoreBoard = new ScoreBoard({ - pageType: match.pageType, - parent: $h, - responseDataKey: 'matchSummary', - autoupdated: match.isLive, - }); - - renderNav( - match, - (resp, $nav, endpoint): void => { - // Test if template is not composed of just whitspace. A content validation check, apparently. - if (!/^\s+$/.test(scoreBoard.template || '')) { - scoreBoard.endpoint = endpoint; - scoreBoard.loadFromJson(resp.matchSummary); - } else { - $h.removeClass('u-h'); - } - - // match stats - if (resp.hasStarted && $nav) { - const statsUrl = $('.tab--stats a', $nav) - .attr('href') - .replace(/^.*\/\/[^/]+/, ''); - - $.create( - `
` - ).each(container => { - statsFor(statsUrl) - .fetch(container) - .then(() => { - // Chart is passed through seperately as when injected with the rest of the content it isn't responsive in Chrome - let chart; - $('.js-chart', container).each(el => { - chart = new TableDoughnut().render( - el - ); - }); - extras[0] = { - name: 'Match stats', - importance: 3, - content: container, - ready: true, - chart, - }; - renderExtras(extras); - }); - }); - } else { - delete extras[0]; - renderExtras(extras); - } - - // Group table & Match day - isCompetition((competition: string) => { - extras[1] = { - ready: false, - }; - - // Group table - if (resp.group !== '') { - renderTable( - `${competition}/${resp.group}`, - extras - ); - } - - // Other games today - $.create( - ` -
- ` - ).each(container => { - matchDayFor(competition, resp.matchDate) - .fetch(container) - .then(() => { - extras[1] = { - name: 'Today’s matches', - importance: 2, - content: container, - ready: true, - }; - renderExtras(extras); - }) - .catch(() => { - delete extras[1]; - renderExtras(extras); - }); - }); - }); - } - ); - } - } - ); - - isCompetition((competition: string) => { - const $rightHandCol = $('.js-secondary-column').dim().height; - if ($rightHandCol === 0 || $rightHandCol > 1800) { - renderTable(competition, extras); - } - }); - - isFootballStatsPage(() => { - console.log('stats page'); - $('.js-chart').each(el => { - $('.football-possession').append(new TableDoughnut().render(el)); - }); - }); - - isLiveClockwatch(() => { - const ml = new MatchListLive( - 'match-day', - isCompetition() || 'premierleague', - config.dateFromSlug() - ); - const $img = $('.media-primary'); - const $matchListContainer = $.create( - // $FlowFixMe - `
- `.css({ minHeight: $img[0] ? $img[0].offsetHeight : 0 }) - ); - - $img.addClass('u-h'); - - loading($matchListContainer[0], 'Fetching today’s matches…', { - text: 'Impatient?', - href: '/football/live', - }); - - $('.js-football-meta').append($matchListContainer); - - const handleResponse = (success: boolean): void => { - if ( - !success || - $('.football-match', $matchListContainer[0]).length === 0 - ) { - ml.destroy(); - $matchListContainer.remove(); - $img.removeClass('u-h'); - } - - $matchListContainer.css({ minHeight: 0 }); - loaded($matchListContainer[0]); - }; - - ml.fetch($matchListContainer[0]) - .then(() => { - handleResponse(true); - }) - .catch(() => { - handleResponse(false); - }); - }); - - // Binding - bean.on( - document.body, - 'click', - '.js-show-more-football-matches', - (e: Event): void => { - e.preventDefault(); - - const el = e.currentTarget; - - if (el && el instanceof HTMLAnchorElement) { - const href = el.getAttribute('href'); - const putsMore = el.getAttribute('data-puts-more-into'); - const newData = el.getAttribute('data-new-url'); - - if (href && putsMore && newData) { - fetchJson(`${href}.json`) - .then(resp => { - $.create(resp.html).each(html => { - const htmlContainer = document.querySelector( - `[data-show-more-contains="${putsMore}"]` - ); - - if (htmlContainer) { - replaceLocaleTimestamps(html); - htmlContainer.appendChild(html); - } - - const nurl = resp[newData]; - - if (nurl) { - bonzo(el).attr('href', nurl); - } else { - bonzo(el).remove(); - } - }); - }) - .catch(ex => { - reportError(ex, { - feature: 'football-show-more', - }); - }); - } - } - } - ); - - bean.on( - document.body, - 'change', - $('form.football-leagues')[0], - function onChange() { - window.location = this.value; - } - ); - - tagPageStats(); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/identity-common.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/identity-common.js deleted file mode 100644 index 9a5610a7698..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/identity-common.js +++ /dev/null @@ -1,37 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/identity-common.js - * to .ts, then delete it. - */ - -// @flow - -/** - * Identity crap that has to run on every page (putting in usernames, avatars, etc.) - * - * Explicitly NOT stuff that only runs on the identity pages. Put that in profile.js or I will hunt you down. I WILL - * HUNT YOU DOWN. - */ -import { catchErrorsWithContext } from 'lib/robust'; -import { isUserLoggedIn } from 'common/modules/identity/api'; - -// Used to show elements that need signin. Use .sign-in-required -const setCssClass = (): void => { - if (!isUserLoggedIn() || !document.documentElement) { - return; - } - const classList = document.documentElement.classList; - - classList.add('id--signed-in'); - classList.remove('id--signed-out'); -}; - -export const init = (): void => { - catchErrorsWithContext([['i-css-class', setCssClass]]); -}; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/liveblog.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/liveblog.js deleted file mode 100644 index 1f0ef30b9be..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/liveblog.js +++ /dev/null @@ -1,80 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/liveblog.js - * to .ts, then delete it. - */ - -// @flow -import config from 'lib/config'; -import { isBreakpoint } from 'lib/detect'; -import mediator from 'lib/mediator'; -import { upgradeRichLinks } from 'common/modules/article/rich-links'; -import { Affix } from 'common/modules/experiments/affix'; -import { autoUpdate } from 'common/modules/ui/autoupdate'; -import { init as initRelativeDates } from 'common/modules/ui/relativedates'; -import { init as initLiveblogCommon } from 'bootstraps/enhanced/article-liveblog-common'; -import { initTrails } from 'bootstraps/enhanced/trail'; -import { catchErrorsWithContext } from 'lib/robust'; - -const affixTimeline = (): void => { - const keywordIds = config.get('page.keywordIds', ''); - - if ( - isBreakpoint({ - min: 'desktop', - }) && - !keywordIds.includes('football/football') && - !keywordIds.includes('sport/rugby-union') - ) { - // eslint-disable-next-line no-new - new Affix({ - element: document.querySelector( - '.js-live-blog__sticky-components-container' - ), - topMarker: document.querySelector('.js-top-marker'), - bottomMarker: document.querySelector('.js-bottom-marker'), - containerElement: document.querySelector( - '.js-live-blog__sticky-components' - ), - }); - } -}; - -const createAutoUpdate = (): void => { - if (config.get('page.isLive')) { - autoUpdate(); - } -}; - -const keepTimestampsCurrent = (): void => { - window.setInterval(() => initRelativeDates(), 60000); -}; - -const init = (): void => { - catchErrorsWithContext([ - ['lb-autoupdate', createAutoUpdate], - ['lb-timeline', affixTimeline], - ['lb-timestamp', keepTimestampsCurrent], - ['lb-richlinks', upgradeRichLinks], - ]); - - initTrails(); - initLiveblogCommon(); - - catchErrorsWithContext([ - [ - 'lb-ready', - () => { - mediator.emit('page:liveblog:ready'); - }, - ], - ]); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/main.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/main.js deleted file mode 100644 index a35b514a468..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/main.js +++ /dev/null @@ -1,413 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/main.js - * to .ts, then delete it. - */ - -// @flow -import fastdom from 'lib/fastdom-promise'; -import qwery from 'qwery'; -import raven from 'lib/raven'; -import $ from 'lib/$'; -import config from 'lib/config'; -import { markTime } from 'lib/user-timing'; -import { catchErrorsWithContext } from 'lib/robust'; -import { runAndTrackAbTests } from 'common/modules/experiments/ab'; -import { initSport } from 'bootstraps/enhanced/sport'; -import { trackPerformance } from 'common/modules/analytics/google'; -import { init as geolocationInit } from 'lib/geolocation'; -import { init as initAcquisitionsLinkEnrichment } from 'common/modules/commercial/acquisitions-link-enrichment'; -import {fetchAndRenderEpic} from "common/modules/commercial/contributions-service"; - -const bootEnhanced = (): void => { - const bootstrapContext = (featureName, bootstrap) => { - raven.context( - { - tags: { - feature: featureName, - }, - }, - bootstrap, - [] - ); - }; - - markTime('App Begin'); - - catchErrorsWithContext([ - [ - 'ga-user-timing-enhanced-start', - () => { - trackPerformance( - 'Javascript Load', - 'enhancedStart', - 'Enhanced start parse time' - ); - }, - ], - - // - // A/B tests - // - - [ - 'ab-tests', - () => { - catchErrorsWithContext([ - [ - 'ab-tests-run', - () => { - runAndTrackAbTests(); - }, - ], - ]); - }, - ], - - ['enrich-acquisition-links', initAcquisitionsLinkEnrichment], - - ['remote-epics', fetchAndRenderEpic ] - ]); - - /** common sets up many things that subsequent modules may need. - * here we make sure it runs first; it's a nice way to avoid - * race conditions caused by one of the modules below having - * a transitive dependency on a module that has already been - * loaded. - */ - import(/* webpackMode: "eager" */ 'bootstraps/enhanced/common') - .then(({ init }) => { - bootstrapContext('common', init); - }) - .then(() => { - // geolocation - catchErrorsWithContext([['geolocation', geolocationInit]]); - - // Front - if (config.get('page.isFront')) { - require.ensure( - [], - require => { - bootstrapContext( - 'facia', - require('bootstraps/enhanced/facia').init - ); - }, - 'facia' - ); - } - - if ( - config.get('page.contentType') === 'Article' && - !config.get('page.isMinuteArticle') - ) { - require.ensure( - [], - require => { - bootstrapContext( - 'article', - require('bootstraps/enhanced/article').init - ); - bootstrapContext( - 'article : lightbox', - require('common/modules/gallery/lightbox').init - ); - }, - 'article' - ); - } - - if (config.get('page.contentType') === 'Crossword') { - require.ensure( - [], - require => { - bootstrapContext( - 'crosswords', - require('bootstraps/enhanced/crosswords').init - ); - }, - 'crosswords' - ); - } - - if (config.get('page.contentType') === 'LiveBlog') { - require.ensure( - [], - require => { - bootstrapContext( - 'liveBlog', - require('bootstraps/enhanced/liveblog').init - ); - bootstrapContext( - 'liveBlog : lightbox', - require('common/modules/gallery/lightbox').init - ); - }, - 'live-blog' - ); - } - - if (config.get('page.isMinuteArticle')) { - require.ensure( - [], - require => { - bootstrapContext( - 'articleMinute', - require('bootstraps/enhanced/article-minute').init - ); - bootstrapContext( - 'article : lightbox', - require('common/modules/gallery/lightbox').init - ); - }, - 'article-minute' - ); - } - - if ( - config.get('page.contentType') === 'Audio' || - config.get('page.contentType') === 'Video' || - config.get('page.contentType') === 'Interactive' - ) { - require.ensure( - [], - require => { - bootstrapContext( - 'media : trail', - require('bootstraps/enhanced/trail').initTrails - ); - }, - 'trail' - ); - } - - fastdom - .measure(() => qwery('audio')) - .then(els => { - if (els.length) { - require.ensure( - [], - require => { - bootstrapContext( - 'media-player', - require('bootstraps/enhanced/media-player') - .initMediaPlayer - ); - }, - 'media-player' - ); - } - }); - - // Native video player enhancements - fastdom - .measure(() => qwery('video')) - .then(els => { - if (els.length) { - require.ensure( - [], - require => { - bootstrapContext( - 'video-player', - require('bootstraps/enhanced/video-player') - .initVideoPlayer - ); - }, - 'video-player' - ); - } - }); - - if (config.get('page.contentType') === 'Gallery') { - require.ensure( - [], - require => { - bootstrapContext( - 'gallery', - require('bootstraps/enhanced/gallery').init - ); - bootstrapContext( - 'gallery : lightbox', - require('common/modules/gallery/lightbox').init - ); - }, - 'gallery' - ); - } - - if (config.get('page.contentType') === 'ImageContent') { - require.ensure( - [], - require => { - bootstrapContext( - 'image-content : lightbox', - require('common/modules/gallery/lightbox').init - ); - bootstrapContext( - 'image-content : trail', - require('bootstraps/enhanced/trail').initTrails - ); - }, - 'image-content' - ); - } - - if (config.get('page.section') === 'football') { - require.ensure( - [], - require => { - bootstrapContext( - 'football', - require('bootstraps/enhanced/football').init - ); - }, - 'football' - ); - } - - if (config.get('page.section') === 'sport') { - // Leaving this here for now as it's a tiny bootstrap. - bootstrapContext('sport', initSport); - } - - if (config.get('page.section') === 'identity') { - require.ensure( - [], - require => { - bootstrapContext( - 'profile', - require('bootstraps/enhanced/profile').initProfile - ); - }, - 'profile' - ); - } - - if (config.get('page.isPreferencesPage')) { - require.ensure( - [], - require => { - bootstrapContext( - 'preferences', - require('bootstraps/enhanced/preferences').init - ); - }, - 'preferences' - ); - } - - if (config.get('page.section') === 'newsletter-signup-page') { - require.ensure( - [], - require => { - bootstrapContext( - 'newsletters', - require('bootstraps/enhanced/newsletters').init - ); - }, - 'newsletters' - ); - } - - // use a #force-sw hash fragment to force service worker registration for local dev - if ( - (window.location.protocol === 'https:' && - config.get('page.section') !== 'identity') || - window.location.hash.indexOf('force-sw') > -1 - ) { - const navigator = window.navigator; - - if (navigator && navigator.serviceWorker) { - if (config.get('switches.serviceWorkerEnabled')) { - navigator.serviceWorker.register('/service-worker.js'); - } else { - navigator.serviceWorker - .getRegistrations() - .then(registrations => { - [...registrations].forEach(registration => { - registration.unregister(); - }); - }); - } - } - } - - if (config.get('page.pageId') === 'help/accessibility-help') { - require.ensure( - [], - require => { - bootstrapContext( - 'accessibility', - require('bootstraps/enhanced/accessibility').init - ); - }, - 'accessibility' - ); - } - - fastdom.measure(() => { - if ($('.youtube-media-atom').length > 0) { - require.ensure( - [], - require => { - bootstrapContext( - 'youtube', - require('bootstraps/enhanced/youtube').init - ); - }, - 'youtube' - ); - } - }); - - if (window.location.hash.includes('experiments')) { - require.ensure( - [], - require => { - bootstrapContext( - 'experiments', - require('common/modules/experiments') - .showExperiments - ); - }, - 'experiments' - ); - } - - if (config.get('page.contentType') === 'Audio') { - require.ensure( - [], - require => { - bootstrapContext( - 'audio', - require('common/modules/audio').init - ); - }, - 'audio' - ); - } - - // Mark the end of synchronous execution. - markTime('App End'); - catchErrorsWithContext([ - [ - 'ga-user-timing-enhanced-end', - () => { - trackPerformance( - 'Javascript Load', - 'enhancedEnd', - 'Enhanced end parse time' - ); - }, - ], - ]); - }); -}; - -export { bootEnhanced }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/media-player.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/media-player.js deleted file mode 100644 index 22b474aa803..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/media-player.js +++ /dev/null @@ -1,313 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/media-player.js - * to .ts, then delete it. - */ - -// @flow - -import videojs from 'videojs'; -import 'videojs-ima'; -import 'videojs-embed'; -import 'videojs-persistvolume'; -import 'videojs-playlist'; -import 'videojs-contrib-ads'; -import bean from 'bean'; -import bonzo from 'bonzo'; -import fastdom from 'fastdom'; -import raven from 'lib/raven'; -import $ from 'lib/$'; -import config from 'lib/config'; -import deferToAnalytics from 'lib/defer-to-analytics'; -import { isBreakpoint } from 'lib/detect'; -import mediator from 'lib/mediator'; -import events from 'common/modules/video/events'; -import videojsOptions from 'common/modules/video/videojs-options'; -import loadingTmpl from 'raw-loader!common/views/ui/loading.html'; -import { isOn as accessibilityisOn } from 'common/modules/accessibility/main'; -import { Component } from 'common/modules/component'; -import { getVideoInfo, isGeoBlocked } from 'common/modules/video/metadata'; -import { fullscreener } from 'common/modules/media/videojs-plugins/fullscreener'; - -const initLoadingSpinner = (player: any): void => { - player.loadingSpinner.contentEl().innerHTML = loadingTmpl; -}; - -const upgradeVideoPlayerAccessibility = (player: any): void => { - // Set the video tech element to aria-hidden, and label the buttons in the videojs control bar. - $('.vjs-tech', player.el()).attr('aria-hidden', true); - - // Hide superfluous controls, and label useful buttons. - $('.vjs-big-play-button', player.el()).attr('aria-hidden', true); - $('.vjs-current-time', player.el()).attr('aria-hidden', true); - $('.vjs-time-divider', player.el()).attr('aria-hidden', true); - $('.vjs-duration', player.el()).attr('aria-hidden', true); - $('.vjs-embed-button', player.el()).attr('aria-hidden', true); - - $('.vjs-play-control', player.el()).attr('aria-label', 'video play'); - $('.vjs-mute-control', player.el()).attr('aria-label', 'video mute'); - $('.vjs-fullscreen-control', player.el()).attr( - 'aria-label', - 'video fullscreen' - ); -}; - -const createVideoPlayer = (el: HTMLElement, options: Object): any => { - const player = videojs(el, options); - - const duration = parseInt(el.getAttribute('data-duration'), 10); - - player.ready(() => { - if (!Number.isNaN(duration)) { - player.duration(duration); - player.trigger('timeupdate'); // triggers a refresh of relevant control bar components - } - // we have some special autoplay rules, so do not want to depend on 'default' autoplay - player.guAutoplay = $(el).attr('data-auto-play') === 'true'; - }); - - return player; -}; - -const initEndSlate = (player: any, endSlatePath: string): void => { - const endSlate = new Component(); - const endStateClass = 'vjs-has-ended'; - - endSlate.endpoint = endSlatePath; - - player.one(events.constructEventName('content:play', player), () => { - endSlate.fetch(player.el(), 'html'); - - player.on('ended', () => { - bonzo(player.el()).addClass(endStateClass); - }); - }); - - player.on('playing', () => { - bonzo(player.el()).removeClass(endStateClass); - }); -}; - -const enhanceVideo = (el: HTMLMediaElement, autoplay: boolean): any => { - const mediaType = el.tagName.toLowerCase(); - const dataset = el.dataset; - const { mediaId, endSlate, embedPath } = dataset; - - // we need to look up the embedPath for main media videos - const canonicalUrl = dataset.canonicalUrl || (embedPath || null); - - // the fallback to window.location.pathname should only happen for main media on fronts - const gaEventLabel = canonicalUrl || window.location.pathname; - - let mouseMoveIdle; - let playerSetupComplete; - - el.classList.add('vjs'); - - // end-slate url follows the patten /video/end-slate/section/
.json?shortUrl= - // only show end-slate if page has a section i.e. not on the `/global` path - // e.g https://www.theguardian.com/global/video/2016/nov/01/what-happened-at-the-battle-of-orgreave-video-explainer - const showEndSlate = - dataset.showEndSlate === 'true' && !!config.get('page.section'); - - const player = createVideoPlayer( - el, - videojsOptions({ - plugins: { - embed: { - embeddable: - !config.get('page.isFront') && - config.get('switches.externalVideoEmbeds') && - (config.get('page.contentType') === 'Video' || - dataset.embeddable === 'true'), - location: `${config.get( - 'page.externalEmbedHost' - )}/embed/video/${embedPath || config.get('page.pageId')}`, - }, - }, - }) - ); - - events.addContentEvents(player, mediaId, mediaType); - events.bindGoogleAnalyticsEvents(player, gaEventLabel); - - getVideoInfo(el).then(videoInfo => { - if (videoInfo.expired) { - player.ready(() => { - player.error({ - code: 0, - type: 'Video Expired', - message: - 'This video has been removed. This could be because it launched early, ' + - 'our rights have expired, there was a legal issue, or for another reason.', - }); - player.bigPlayButton.dispose(); - player.errorDisplay.open(); - player.controlBar.dispose(); - }); - } else { - isGeoBlocked(el).then(isVideoGeoBlocked => { - if (isVideoGeoBlocked) { - player.ready(() => { - player.error({ - code: 0, - type: 'Video Unavailable', - message: - 'Sorry, this video is not available in your region due to rights restrictions.', - }); - player.bigPlayButton.dispose(); - player.errorDisplay.open(); - player.controlBar.dispose(); - }); - } else { - // Location of this is important. - events.bindErrorHandler(player); - player.guMediaType = mediaType; - - playerSetupComplete = new Promise(resolve => { - player.ready(() => { - deferToAnalytics(() => { - events.initOphanTracking(player, mediaId); - events.bindGlobalEvents(player); - events.bindContentEvents(player); - }); - - initLoadingSpinner(player); - upgradeVideoPlayerAccessibility(player); - - // unglitching the volume on first load - const vol = player.volume(); - - if (vol) { - player.volume(0); - player.volume(vol); - } - - player.persistvolume({ - namespace: 'gu.vjs', - }); - - if (mediaType === 'video') { - player.fullscreener(); - - if ( - showEndSlate && - isBreakpoint({ - min: 'desktop', - }) - ) { - initEndSlate(player, endSlate); - } - } else { - player.playlist({ - mediaType: 'audio', - continuous: false, - }); - } - - resolve(); - - // built in vjs-user-active is buggy so using custom implementation - player.on('mousemove', () => { - clearTimeout(mouseMoveIdle); - fastdom.mutate(() => { - player.addClass('vjs-mousemoved'); - }); - - mouseMoveIdle = setTimeout(() => { - fastdom.mutate(() => { - player.removeClass('vjs-mousemoved'); - }); - }, 500); - }); - }); - }); - - playerSetupComplete.then(() => { - if ( - autoplay && - accessibilityisOn('flashing-elements') - ) { - player.play(); - } - }); - } - }); - } - }); - - return player; -}; - -const initPlayButtons = (root: ?HTMLElement): void => { - fastdom.measure(() => { - $('.js-video-play-button', root).each(el => { - const $el = bonzo(el); - bean.on(el, 'click', () => { - const container = bonzo(el) - .parent() - .parent(); - const placeholder = $('.js-video-placeholder', container); - const player = $('.js-video-player', container); - - fastdom.mutate(() => { - placeholder - .removeClass('media__placeholder--active') - .addClass('media__placeholder--hidden'); - player - .removeClass('media__container--hidden') - .addClass('media__container--active'); - $el.removeClass('media__placeholder--active').addClass( - 'media__placeholder--hidden' - ); - enhanceVideo($('video', player).get(0), true); - }); - }); - fastdom.mutate(() => { - $el.removeClass('media__placeholder--hidden').addClass( - 'media__placeholder--active' - ); - }); - }); - }); -}; - -const initPlayer = (): void => { - videojs.plugin('fullscreener', fullscreener); - - fastdom.measure(() => { - $('.js-gu-media--enhance').each(el => { - enhanceVideo(el, false); - }); - }); -}; - -const initWithRaven = (): void => { - raven.wrap( - { - tags: { - feature: 'media', - }, - }, - () => { - initPlayer(); - } - )(); -}; - -export const initMediaPlayer = (): void => { - initWithRaven(); - - // Setup play buttons - initPlayButtons(document.body); - mediator.on('modules:related:loaded', initPlayButtons); - mediator.on('page:media:moreinloaded', initPlayButtons); -}; - -export { videojs }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/membership.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/membership.js deleted file mode 100644 index 70732de5af6..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/membership.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/membership.js - * to .ts, then delete it. - */ - -// @flow -import { deleteOldData } from 'common/modules/commercial/user-features'; - -export const init = (): void => { - deleteOldData(); -}; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/newsletters.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/newsletters.js deleted file mode 100644 index 143995b5a3a..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/newsletters.js +++ /dev/null @@ -1,168 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/newsletters.js - * to .ts, then delete it. - */ - -// @flow -import bean from 'bean'; -import fastdom from 'fastdom'; -import $ from 'lib/$'; -import fetch from 'lib/fetch'; -import config from 'lib/config'; -import { getUserFromCookie, getUserFromApi } from 'common/modules/identity/api'; - -const classes = { - wrapper: 'js-newsletter-meta', - signupForm: 'js-email-sub__form', - textInput: 'js-newsletter-card__text-input', - signupButton: 'js-newsletter-signup-button', - styleSignup: 'newsletter-card__lozenge--submit', - signupConfirm: 'js-signup-confirmation', - previewButton: 'js-newsletter-preview', -}; - -const inputs = { - email: 'email', - dummy: 'name', -}; - -const hideInputAndShowPreview = (el: ?Node): void => { - fastdom.mutate(() => { - $(`.${classes.textInput}`, el).addClass('is-hidden'); - $(`.${classes.signupButton}`, el).removeClass(classes.styleSignup); - $(`.${classes.previewButton}`, el).removeClass('is-hidden'); - }); -}; - -const validate = (form: ?HTMLFormElement): boolean => { - // simplistic email address validation - const emailAddress = $(`.${classes.textInput}`, form).val(); - return typeof emailAddress === 'string' && emailAddress.indexOf('@') > -1; -}; - -const addSubscriptionMessage = (buttonEl: HTMLButtonElement): void => { - const meta = $.ancestor(buttonEl, classes.wrapper); - fastdom.mutate(() => { - $(buttonEl.form).addClass('is-hidden'); - $(`.${classes.previewButton}`, meta).addClass('is-hidden'); - $(`.${classes.signupConfirm}`, meta).removeClass('is-hidden'); - }); -}; - -const modifyDataLinkName = (modifier: string) => (el: HTMLButtonElement) : void => { - const firstStageName = el.getAttribute('data-link-name') || "undefined-data-link-name" - el.setAttribute('data-link-name', firstStageName + modifier) -} - -const modifyLinkNamesForSecondStage = (el: HTMLButtonElement) => modifyDataLinkName('-second-stage')(el) - -const modifyLinkNamesForSignedInUser = (el: HTMLButtonElement) => modifyDataLinkName('-signed-in')(el) - -const submitForm = ( - form: ?HTMLFormElement, - buttonEl: HTMLButtonElement -): Promise => { - const dummyEmail = encodeURIComponent( - $(`input[name="${inputs.dummy}"]`, form).val() - ); // Used as a 'bot-bait', see https://stackoverflow.com/a/34623588/2823715 - const email = encodeURIComponent( - $(`input[name="${inputs.email}"]`, form).val() - ); - const listName = encodeURIComponent( - $('input[name="listName"]', form).val() - ); - const csrfToken = encodeURIComponent( - $('input[name="csrfToken"]', form).val() - ); - const formQueryString = `${ - inputs.email - }=${email}&csrfToken=${csrfToken}&listName=${listName}&${ - inputs.dummy - }=${dummyEmail}`; - - return fetch(`${config.get('page.ajaxUrl')}/email`, { - method: 'POST', - body: formQueryString, - headers: { - Accept: 'application/json', - 'Content-Type': 'application/x-www-form-urlencoded', - }, - }).then(response => { - if (response.ok) { - addSubscriptionMessage(buttonEl); - } - }); -}; - -const createSubscriptionFormEventHandlers = (buttonEl: HTMLButtonElement): void => { - bean.on(buttonEl, 'click', event => { - event.preventDefault(); - const form = buttonEl.form; - if (validate(form)) { - submitForm(form, buttonEl); - } - }); -}; - -const modifyFormForSignedIn = (el) => { - modifyLinkNamesForSignedInUser(el); - createSubscriptionFormEventHandlers(el); -} - -const showSignupForm = (buttonEl: HTMLButtonElement): void => { - const form = buttonEl.form; - const meta = $.ancestor(buttonEl, 'js-newsletter-meta'); - fastdom.mutate(() => { - $(`.${classes.textInput}`, form) - .removeClass('is-hidden') - .focus(); - $(`.${classes.signupButton}`, form).addClass(classes.styleSignup); - $(`.${classes.previewButton}`, meta).addClass('is-hidden'); - modifyLinkNamesForSecondStage(buttonEl) - createSubscriptionFormEventHandlers(buttonEl); - }); -}; - -const updatePageForLoggedIn = (emailAddress: string, el: ?Node): void => { - fastdom.mutate(() => { - hideInputAndShowPreview(el); - $(`.${classes.textInput}`, el).val(emailAddress); - }); -}; - -const showSecondStageSignup = (buttonEl: HTMLButtonElement): void => { - fastdom.mutate(() => { - buttonEl.setAttribute('type', 'button'); - bean.on(buttonEl, 'click', () => { - showSignupForm(buttonEl); - }); - }); -}; - -const enhanceNewsletters = (): void => { - if (getUserFromCookie() !== null) { - // email address is not stored in the cookie, gotta go to the Api - getUserFromApi(userFromId => { - if (userFromId && userFromId.primaryEmailAddress) { - updatePageForLoggedIn(userFromId.primaryEmailAddress); - $.forEachElement(`.${classes.signupButton}`, modifyFormForSignedIn); - } - }); - } else { - hideInputAndShowPreview(); - $.forEachElement(`.${classes.signupButton}`, showSecondStageSignup); - } -}; - -const init = (): void => { - enhanceNewsletters(); -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/preferences.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/preferences.js deleted file mode 100644 index 104d01c0b01..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/preferences.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/preferences.js - * to .ts, then delete it. - */ - -// @flow -import React, { Component, render } from 'preact/compat'; -import { - getPopularFiltered, - deleteFromSummary, - showInMegaNav, - showInMegaNavEnable, - showInMegaNavEnabled, -} from 'common/modules/onward/history'; - -class SummaryTagsList extends Component<*, *> { - constructor() { - super(); - this.state = { - popular: getPopularFiltered(), - }; - } - - handleRemove(tag: string) { - deleteFromSummary(tag); - this.setState({ - popular: getPopularFiltered({ flush: true }), - }); - showInMegaNav(); - } - - render() { - const tagElements = this.state.popular.map(tag => ( - - - {tag[1]} - - )); - - let helperText; - - if (!tagElements.length) { - helperText = "(You don't have any recently visited topics.)"; - } else { - helperText = - "Remove individual topics by clicking 'X' or switch off the functionality below. We respect your privacy and your shortcuts will never be made public."; - } - tagElements.push(

{helperText}

); - - return
{tagElements}
; - } -} - -class SummaryTagsSettings extends Component<*, *> { - constructor() { - super(); - this.state = { - enabled: showInMegaNavEnabled(), - }; - } - - handleToggle() { - const isEnabled = !this.state.enabled; - - this.setState({ - enabled: isEnabled, - }); - showInMegaNavEnable(isEnabled); - } - - render() { - const toggleAction = this.state.enabled ? 'OFF' : 'ON'; - - return ( -
-

- These are based on the topics you visit most. You can access - them at any time by opening the "all sections" - menu. -

- {this.state.enabled ? : null} - -
- ); - } -} - -const init = (): void => { - const placeholder: ?HTMLElement = document.getElementById( - 'preferences-history-tags' - ); - - if (placeholder) { - render(, placeholder); - } -}; - -export { init }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/profile.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/profile.js deleted file mode 100644 index 8e52091ae9f..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/profile.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/profile.js - * to .ts, then delete it. - */ - -// @flow - -import { catchErrorsWithContext } from 'lib/robust'; -import { forgottenEmail, passwordToggle } from 'common/modules/identity/forms'; -import { Formstack } from 'common/modules/identity/formstack'; -import { FormstackIframe } from 'common/modules/identity/formstack-iframe'; -import { FormstackEmbedIframe } from 'common/modules/identity/formstack-iframe-embed'; -import { init as initValidationEmail } from 'common/modules/identity/validation-email'; -import { AccountProfile } from 'common/modules/identity/account-profile'; -import { init as initPublicProfile } from 'common/modules/identity/public-profile'; -import { enhanceFormAjax } from 'common/modules/identity/form-ajax'; -import { enhanceConsents } from 'common/modules/identity/consents'; -import { enhanceConsentJourney } from 'common/modules/identity/consent-journey'; -import { setupLoadingAnimation } from 'common/modules/identity/delete-account'; -import { initHeader } from 'common/modules/identity/header'; -import { initUserAvatars } from 'common/modules/discussion/user-avatars'; -import { initUserEditLink } from 'common/modules/discussion/user-edit-link'; -import { init as initTabs } from 'common/modules/ui/tabs'; -import { enhanceAdPrefs } from 'common/modules/identity/ad-prefs'; -import { enhanceUpsell } from 'common/modules/identity/upsell/upsell'; - -const initFormstack = (): void => { - const attr = 'data-formstack-id'; - const forms = Array.from(document.querySelectorAll(`[${attr}]`)); - const iframes = Array.from( - document.getElementsByClassName('js-formstack-iframe') - ); - - forms.forEach(form => { - const id = form.getAttribute(attr) || ''; - const isEmbed = form.className.match(/\bformstack-embed\b/); - - if (isEmbed) { - new FormstackEmbedIframe(form, id).init(); - } else { - new Formstack(form, id).init(); - } - }); - - // Load old js if necessary - iframes.forEach(el => { - const iframe: HTMLIFrameElement = (el: any); - - new FormstackIframe(iframe).init(); - }); -}; - -const initAccountProfile = (): void => { - // eslint-disable-next-line no-new - new AccountProfile(); -}; - -const initProfile = (): void => { - const modules: Array> = [ - ['init-form-stack', initFormstack], - ['forgotten-email', forgottenEmail], - ['password-toggle', passwordToggle], - ['init-validation-email', initValidationEmail], - ['init-user-avatars', initUserAvatars], - ['init-user-edit-link', initUserEditLink], - ['init-tabs', initTabs], - ['init-account-profile', initAccountProfile], - ['setup-loading-animation', setupLoadingAnimation], - ['init-public-profile', initPublicProfile], - ['enhance-consents', enhanceConsents], - ['enhance-ad-prefs', enhanceAdPrefs], - ['enhance-form-ajax', enhanceFormAjax], - ['enhance-consent-journey', enhanceConsentJourney], - ['init-header', initHeader], - ['init-upsell', enhanceUpsell], - ]; - catchErrorsWithContext(modules); -}; - -export { initProfile }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/sport.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/sport.js deleted file mode 100644 index 8f557467d4c..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/sport.js +++ /dev/null @@ -1,193 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/sport.js - * to .ts, then delete it. - */ - -// @flow - -import $ from 'lib/$'; -import { Component } from 'common/modules/component'; -import config from 'lib/config'; -import fastdom from 'lib/fastdom-promise'; -import { isBreakpoint } from 'lib/detect'; -import { TableDoughnut } from 'common/modules/charts/table-doughnut'; -import { belowArticleVisible } from 'lib/page'; -import { ScoreBoard } from 'common/modules/sport/score-board'; -import { addComponent as addRhcComponent } from 'common/modules/ui/rhc'; -import template from 'lodash/template'; - -declare type Extra = { - name: string, - importance: number, - content: HTMLElement, - ready: boolean, -}; - -const renderExtras = (extras: Array): void => { - if (extras.filter(extra => extra && extra.ready === false).length === 0) { - belowArticleVisible( - () => { - $('.js-after-article').append( - $.create('
').each( - extrasContainer => { - extras.forEach(extra => { - extrasContainer.appendChild(extra.content); - }); - } - ) - ); - }, - () => { - extras.forEach(extra => { - addRhcComponent(extra.content, extra.importance); - }); - } - ); - } -}; - -const cricket = (): void => { - const matchDate = config.get('page.cricketMatchDate'); - const team = config.get('page.cricketTeam'); - - if (matchDate && team) { - const cricketScore = new Component(); - cricketScore.endpoint = `/sport/cricket/match/${matchDate}/${team}.json`; - - fastdom - .measure(() => document.querySelector('.js-cricket-score')) - .then(parentEl => { - cricketScore.fetch(parentEl, 'summary'); - }); - } -}; - -const rugby = (): void => { - let pageType = ''; - - if (config.get('page.isLiveBlog')) { - pageType = 'minbymin'; - } else if (config.hasTone('Match reports')) { - pageType = 'report'; - } - - if (config.get('page.rugbyMatch') && pageType) { - const page = encodeURIComponent(config.get('page.pageId')); - - const scoreBoard = new ScoreBoard({ - pageType, - parent: $('.js-score'), - autoupdated: config.get('page.isLive'), - responseDataKey: 'matchSummary', - endpoint: `${config.get('page.rugbyMatch')}.json?page=${page}`, - }); - - // Rugby score returns the match nav too, to optimise calls. - // $FlowFixMe - scoreBoard.fetched = (resp: Object): void => { - fastdom - .measure(() => document.querySelector('article')) - .then(liveblog => { - liveblog.classList.add('content--has-scores'); - }); - - fastdom - .measure(() => document.querySelector('.content--liveblog')) - .then(liveblog => { - liveblog.classList.add('content--liveblog--rugby'); - }); - - $.create(resp.nav) - .first() - .each(nav => { - // There ought to be exactly two tabs; match report and min-by-min - if ($('.tabs__tab', nav).length === 2) { - $('.js-sport-tabs').empty(); - $('.js-sport-tabs').append(nav); - } - }); - - const contentString = resp.scoreEvents; - - if (isBreakpoint({ max: 'mobile' })) { - const $scoreEventsMobile = $.create( - template(resp.dropdown)({ - name: 'Score breakdown', - content: contentString, - }) - ); - - if (config.get('page.isLiveBlog')) { - $scoreEventsMobile.addClass('dropdown--key-events'); - } - - $scoreEventsMobile.addClass('dropdown--active'); - - $('.js-after-article').append($scoreEventsMobile); - } else { - const $scoreEventsTabletUp = $.create(contentString); - - $scoreEventsTabletUp.addClass('hide-on-mobile'); - - $('.rugby-stats').remove(); - $('.score-container').after($scoreEventsTabletUp); - } - - $('.js-match-stats').remove(); - if (resp.matchStat) { - $.create( - `
${ - resp.matchStat - }
` - ).each(container => { - $('.js-chart', container).each(el => { - new TableDoughnut().render(el); - }); - - renderExtras([ - { - name: 'Match stats', - importance: 3, - content: container, - ready: true, - }, - ]); - }); - } - - $('.js-football-table').remove(); - if (resp.groupTable) { - $.create( - `
${ - resp.groupTable - }
` - ).each(container => { - renderExtras([ - { - name: 'Table', - importance: 3, - content: container, - ready: true, - }, - ]); - }); - } - }; - - scoreBoard.load(); - } -}; - -const initSport = (): void => { - cricket(); - rugby(); -}; - -export { initSport }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/trail.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/trail.js deleted file mode 100644 index 90c09fc1418..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/trail.js +++ /dev/null @@ -1,203 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/trail.js - * to .ts, then delete it. - */ - -// @flow - -/* eslint-disable no-new */ - -import fastdom from 'lib/fastdom-promise'; -import qwery from 'qwery'; -import $ from 'lib/$'; -import config from 'lib/config'; -import { catchErrorsWithContext } from 'lib/robust'; -import { addProximityLoader } from 'lib/proximity-loader'; -import { Loader as DiscussionLoader } from 'common/modules/discussion/loader'; -import { isUserLoggedIn } from 'common/modules/identity/api'; -import { OnwardContent } from 'common/modules/onward/onward-content'; -import { MostPopular } from 'common/modules/onward/popular'; -import { related } from 'common/modules/onward/related'; -import { TonalComponent } from 'common/modules/onward/tonal'; -import { loadShareCounts } from 'common/modules/social/share-count'; -import { onwardVideo } from 'common/modules/video/onward-container'; -import { onwardAudio } from 'common/modules/audio/onward-container'; -import { moreInSeriesContainerInit } from 'common/modules/video/more-in-series-container'; - -const initMoreInSection = (): void => { - const { - showRelatedContent, - isPaidContent, - section, - shortUrl, - seriesId, - } = config.get('page', {}); - - if ( - (config.get('page.contentType') !== 'Audio' && - config.get('page.contentType') !== 'Video') || - !showRelatedContent || - isPaidContent || - !section - ) { - return; - } - - const el = $('.js-more-in-section')[0]; - moreInSeriesContainerInit( - el, - config.get('page.contentType', '').toLowerCase(), - section, - shortUrl, - seriesId - ); -}; - -const insertOrProximity = (selector, insert) => { - if (window.location.hash) { - insert(); - } else { - fastdom - .measure(() => document.querySelector(selector)) - .then(el => { - if (el) { - addProximityLoader(el, 1500, insert); - } - }); - } -}; - -const initPopular = () => { - if (!config.get('page.isFront')) { - insertOrProximity('.js-popular-trails', () => { - new MostPopular(); - }); - } -}; - -const initRelated = () => { - if (!(config.get('page.seriesId') || config.get('page.blogIds'))) { - insertOrProximity('.js-related', () => { - const opts = { - excludeTags: [], - }; - - // exclude ad features from non-ad feature content - if (config.get('page.sponsorshipType') !== 'paid-content') { - opts.excludeTags.push('tone/advertisement-features'); - } - // don't want to show professional network content on videos or interactives - if ( - 'contentType' in config.get('page') && - ['video', 'interactive'].includes( - config.get('page.contentType', '').toLowerCase() - ) - ) { - opts.excludeTags.push( - 'guardian-professional/guardian-professional' - ); - } - - related(opts); - }); - } -}; - -const initOnwardVideoContainer = (): void => { - const contentType = config.get('page.contentType', ''); - - if (contentType !== 'Audio' && contentType !== 'Video') { - return; - } - - const mediaType = contentType.toLowerCase(); - const els = $( - mediaType === 'video' - ? '.js-video-components-container' - : '.js-media-popular' - ); - - els.each(el => { - onwardVideo(el, mediaType); - }); -}; - -const initOnwardAudioContainer = (): void => { - if (config.get('page.contentType') === 'Audio') { - $('.js-audio-components-container').each(el => onwardAudio(el)); - } -}; - -const initOnwardContent = () => { - insertOrProximity('.js-onward', () => { - if ( - (config.get('page.seriesId') || config.get('page.blogIds')) && - config.get('page.showRelatedContent') - ) { - new OnwardContent(qwery('.js-onward')); - } else if (config.get('page.tones', '') !== '') { - fastdom - .measure(() => Array.from(document.querySelectorAll('.js-onward'))) - .then(els => { - els.forEach(c => { - new TonalComponent().fetch(c, 'html'); - }); - }); - } - }); - - initOnwardVideoContainer(); - initOnwardAudioContainer(); -}; - -const initDiscussion = () => { - if ( - config.get('switches.enableDiscussionSwitch') && - config.get('page.commentable') - ) { - fastdom - .measure(() => document.querySelector('.discussion')) - .then(el => { - if (el) { - new DiscussionLoader().attachTo(el); - } - }); - } -}; - -const repositionComments = () => { - if (!isUserLoggedIn()) { - fastdom - .measure(() => $('.js-comments')) - .then($comments => - fastdom.mutate(() => { - $comments.appendTo(qwery('.js-repositioned-comments')); - if (window.location.hash === '#comments') { - const top = $comments.offset().top; - $(document.body).scrollTop(top); - } - }) - ); - } -}; - -const initTrails = () => { - catchErrorsWithContext([ - ['c-discussion', initDiscussion], - ['c-comments', repositionComments], - ['c-shares', loadShareCounts], - ['c-popular', initPopular], - ['c-related', initRelated], - ['c-onward', initOnwardContent], - ['c-more-in-section', initMoreInSection], - ]); -}; - -export { initTrails }; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/video-player.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/video-player.js deleted file mode 100644 index abcd12e787d..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/video-player.js +++ /dev/null @@ -1,135 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/video-player.js - * to .ts, then delete it. - */ - -// @flow - -import fastdom from 'lib/fastdom-promise'; -import $ from 'lib/$'; -import bean from 'bean'; -import raven from 'lib/raven'; -import { - buildGoogleAnalyticsEvent, - getGoogleAnalyticsEventAction, -} from 'common/modules/video/ga-helper'; -import config from 'lib/config'; -import ophan from 'ophan/ng'; - -const gaTracker = config.get('googleAnalytics.trackers.editorial'); -const isEmbed = !!window.guardian.isEmbed; - -const getCanonicalUrl = (dataset: Object): string => - dataset.canonicalUrl || - // we need to look up the embedPath for main media videos - dataset.embedPath || - // the fallback to window.location.pathname should only happen for main media on fronts - window.location.pathname; - -const bindTrackingEvents = (el: HTMLMediaElement): void => { - const mediaType = el.tagName.toLowerCase(); - const dataset = el.dataset; - const { mediaId } = dataset; - const canonicalUrl = getCanonicalUrl(dataset); - - const playHandler = () => { - // on play, fire GA event - const mediaEvent = { - mediaId, - mediaType, - eventType: 'play', - isPreroll: false, - }; - const events = { - play: 'metric1', - }; - - window.ga( - `${gaTracker}.send`, - 'event', - buildGoogleAnalyticsEvent( - mediaEvent, - events, - canonicalUrl, - 'guardian-videojs', - getGoogleAnalyticsEventAction, - mediaId - ) - ); - - // on play, fire Ophan event - const record = ophanEmbed => { - const eventObject = { - video: { - id: mediaId, - eventType: 'video:content:play', - }, - }; - - ophanEmbed.record(eventObject); - }; - - if (isEmbed) { - require.ensure( - [], - require => { - record(require('ophan/embed')); - }, - 'ophan-embed' - ); - } else { - record(ophan); - } - - // don't fire events every time video is paused then restarted - bean.off(el, 'play', playHandler); - }; - - bean.on(el, 'play', playHandler); - bean.on(el, 'ended', () => { - // track re-plays - bean.on(el, 'play', playHandler); - }); - bean.on(el, 'play pause', () => { - // synthetic click on data-component="main video" - const figure: HTMLElement = (el.parentNode && - el.parentNode.parentNode && - el.parentNode.parentNode.parentNode: any); - - figure.click(); - }); -}; - -const initPlayer = (): void => { - fastdom.measure(() => { - $('.js-gu-media--enhance').each(el => { - bindTrackingEvents(el); - // hide download button in Chrome - el.setAttribute('controlsList', 'nodownload'); - }); - }); -}; - -const initWithRaven = (): void => { - raven.wrap( - { - tags: { - feature: 'video', - }, - }, - () => { - initPlayer(); - } - )(); -}; - -export const initVideoPlayer = (): void => { - initWithRaven(); -}; diff --git a/static/src/javascripts.flow.archive/bootstraps/enhanced/youtube.js b/static/src/javascripts.flow.archive/bootstraps/enhanced/youtube.js deleted file mode 100644 index c2205206753..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/enhanced/youtube.js +++ /dev/null @@ -1,19 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/enhanced/youtube.js - * to .ts, then delete it. - */ - -// @flow - -import { checkElemsForVideos } from 'common/modules/atoms/youtube'; - -export const init = () => { - checkElemsForVideos(); -}; diff --git a/static/src/javascripts.flow.archive/bootstraps/standard/atoms.js b/static/src/javascripts.flow.archive/bootstraps/standard/atoms.js deleted file mode 100644 index 07640182897..00000000000 --- a/static/src/javascripts.flow.archive/bootstraps/standard/atoms.js +++ /dev/null @@ -1,166 +0,0 @@ -/** - * DO NOT EDIT THIS FILE - * - * It is not used to to build anything. - * - * It's just a record of the old flow types. - * - * Use it as a guide when converting - * - static/src/javascripts/bootstraps/standard/atoms.js - * to .ts, then delete it. - */ - -// @flow - -import config from 'lib/config'; -import { services } from 'projects/atoms/services'; - -const bootstrapAtom = (atomMaker: AtomMaker, atomType: AtomType) => { - const atomBuilder = atomMaker[atomType].default(services); - Array.from( - document.querySelectorAll(`[data-atom-type='${atomType}']`) - ).forEach(atomDom => { - const atom = atomBuilder(atomDom).runTry(); - if (typeof atom === 'string') { - // eslint-disable-next-line no-console - console.log( - `Failed to initialise atom [${atomType}/${atomDom.getAttribute( - 'data-atom-id' - ) || ''}]: ${atom}` - ); - } else if ('requestIdleCallback' in window) { - requestIdleCallback(() => { - atom.start(); - }); - } else { - atom.start(); - } - }); -}; - -const initCharts = () => { - const iframes: HTMLIFrameElement[] = ([ - ...document.querySelectorAll('.atom--chart > .atom__iframe'), - ]: any); - - window.addEventListener('message', event => { - const iframe: ?HTMLIFrameElement = iframes.find(i => { - try { - return i.name === event.source.name; - } catch (e) { - return false; - } - }); - if (iframe) { - try { - const message = JSON.parse(event.data); - switch (message.type) { - case 'set-height': - iframe.height = message.value; - break; - default: - } - // eslint-disable-next-line no-empty - } catch (e) {} - } - }); - - iframes.forEach(iframe => { - const src = (iframe.getAttribute('srcdoc') || '') - .replace(//g, '