diff --git a/app/client/components/GristDoc.ts b/app/client/components/GristDoc.ts index 3527ae6e..7f776317 100644 --- a/app/client/components/GristDoc.ts +++ b/app/client/components/GristDoc.ts @@ -197,6 +197,7 @@ export class GristDoc extends DisposableWithEvents { private _isRickRowing: Observable = Observable.create(this, false); private _showBackgroundVideoPlayer: Observable = Observable.create(this, false); private _backgroundVideoPlayerHolder: Holder = Holder.create(this); + private _disableAutoStartingTours: boolean = false; constructor( @@ -278,54 +279,56 @@ export class GristDoc extends DisposableWithEvents { // Subscribe to URL state, and navigate to anchor or open a popup if necessary. this.autoDispose(subscribe(urlState().state, async (use, state) => { - if (state.hash) { - try { - if (state.hash.popup) { - await this.openPopup(state.hash); - } else { - // Navigate to an anchor if one is present in the url hash. - const cursorPos = this._getCursorPosFromHash(state.hash); - await this.recursiveMoveToCursorPos(cursorPos, true); - } - if (state.hash.rickRow && !this._isRickRowing.get()) { - YouTubePlayer.create(this._backgroundVideoPlayerHolder, RICK_ROLL_YOUTUBE_EMBED_ID, { - height: '100%', - width: '100%', - origin: getMainOrgUrl(), - playerVars: { - controls: 0, - disablekb: 1, - fs: 0, - iv_load_policy: 3, - modestbranding: 1, - }, - onPlayerStateChange: (_player, event) => { - if (event.data === PlayerState.Playing) { - this._isRickRowing.set(true); - } - }, - }, cssYouTubePlayer.cls('')); - this._showBackgroundVideoPlayer.set(true); - this._waitForView() - .then(() => { - const cursor = document.querySelector('.selected_cursor.active_cursor'); - if (cursor) { - this.behavioralPromptsManager.showTip(cursor, 'rickRow', { - forceShow: true, - hideDontShowTips: true, - markAsSeen: false, - showOnMobile: true, - onDispose: () => this.playRickRollVideo(), - }); - } - }) - .catch(reportError); - } - } catch (e) { - reportError(e); - } finally { - setTimeout(finalizeAnchor, 0); + if (!state.hash) { return; } + + try { + if (state.hash.popup) { + await this.openPopup(state.hash); + } else { + // Navigate to an anchor if one is present in the url hash. + const cursorPos = this._getCursorPosFromHash(state.hash); + await this.recursiveMoveToCursorPos(cursorPos, true); } + + const isTourOrTutorialActive = isTourActive() || this.docModel.isTutorial(); + if (state.hash.rickRow && !this._isRickRowing.get() && !isTourOrTutorialActive) { + YouTubePlayer.create(this._backgroundVideoPlayerHolder, RICK_ROLL_YOUTUBE_EMBED_ID, { + height: '100%', + width: '100%', + origin: getMainOrgUrl(), + playerVars: { + controls: 0, + disablekb: 1, + fs: 0, + iv_load_policy: 3, + modestbranding: 1, + }, + onPlayerStateChange: (_player, event) => { + if (event.data === PlayerState.Playing) { + this._isRickRowing.set(true); + } + }, + }, cssYouTubePlayer.cls('')); + this._showBackgroundVideoPlayer.set(true); + this._waitForView() + .then(() => { + const cursor = document.querySelector('.selected_cursor.active_cursor'); + if (!cursor) { return; } + + this.behavioralPromptsManager.showTip(cursor, 'rickRow', { + forceShow: true, + hideDontShowTips: true, + markAsSeen: false, + showOnMobile: true, + onDispose: () => this.playRickRollVideo(), + }); + }) + .catch(reportError); + } + } catch (e) { + reportError(e); + } finally { + setTimeout(finalizeAnchor, 0); } })); @@ -337,12 +340,17 @@ export class GristDoc extends DisposableWithEvents { return; } - const shouldStartTutorial = this.docModel.isTutorial(); + const isTutorial = this.docModel.isTutorial(); // Onboarding tours were not designed with mobile support in mind. Disable until fixed. - if (isNarrowScreen() && !shouldStartTutorial) { + if (isNarrowScreen() && !isTutorial) { return; } + // Onboarding tours can conflict with rick rowing. + if (state.hash?.rickRow) { + this._disableAutoStartingTours = true; + } + // If we have an active tour or tutorial (or are in the process of starting one), don't start // a new one. const hasActiveTourOrTutorial = isTourActive() || !this._docTutorialHolder.isEmpty(); @@ -350,6 +358,7 @@ export class GristDoc extends DisposableWithEvents { return; } + const shouldStartTutorial = isTutorial; const shouldStartDocTour = state.docTour || this._shouldAutoStartDocTour(); const shouldStartWelcomeTour = state.welcomeTour || this._shouldAutoStartWelcomeTour(); if (shouldStartTutorial || shouldStartDocTour || shouldStartWelcomeTour) { @@ -1438,7 +1447,7 @@ export class GristDoc extends DisposableWithEvents { * seen the tour before. */ private _shouldAutoStartDocTour(): boolean { - if (this.docModel.isTutorial()) { + if (this._disableAutoStartingTours || this.docModel.isTutorial()) { return false; } @@ -1454,7 +1463,7 @@ export class GristDoc extends DisposableWithEvents { private _shouldAutoStartWelcomeTour(): boolean { // If a doc tutorial or tour are available, leave the welcome tour for another // doc (e.g. a new one). - if (this.docModel.isTutorial() || this.docModel.hasDocTour()) { + if (this._disableAutoStartingTours || this.docModel.isTutorial() || this.docModel.hasDocTour()) { return false; } diff --git a/test/nbrowser/DocTutorial.ts b/test/nbrowser/DocTutorial.ts index 2126d4e8..4a0b46c4 100644 --- a/test/nbrowser/DocTutorial.ts +++ b/test/nbrowser/DocTutorial.ts @@ -224,6 +224,16 @@ describe('DocTutorial', function () { assert.isTrue(await driver.find('.test-doc-tutorial-popup-footer').isDisplayed()); }); + it('does not play an easter egg when opening an anchor link encoded with rr', async function() { + await gu.getCell({rowNum: 1, col: 0}).click(); + const link = await gu.getAnchor(); + const easterEggLink = link.replace('r1', 'rr1'); + await driver.get(easterEggLink); + await gu.waitForAnchor(); + assert.isFalse(await driver.find('.test-behavioral-prompt').isPresent()); + await gu.assertIsRickRowing(false); + }); + it('remembers the last slide the user had open', async function() { await driver.find('.test-doc-tutorial-popup-slide-3').click(); // There's a 1000ms debounce in place for updates to the last slide. diff --git a/test/nbrowser/gristUtils.ts b/test/nbrowser/gristUtils.ts index 531735a0..8078542a 100644 --- a/test/nbrowser/gristUtils.ts +++ b/test/nbrowser/gristUtils.ts @@ -3012,6 +3012,15 @@ export async function skipWelcomeQuestions() { } } +/** + * Asserts whether a video of Never Gonna Give You Up is playing in the background. + */ +export async function assertIsRickRowing(expected: boolean) { + assert.equal(await driver.find('.test-gristdoc-stop-rick-rowing').isPresent(), expected); + assert.equal(await driver.find('.test-gristdoc-background-video').isPresent(), expected); + assert.equal(await driver.find('iframe#youtube-player-dQw4w9WgXcQ').isPresent(), expected); +} + } // end of namespace gristUtils stackWrapOwnMethods(gristUtils);