diff --git a/packages/playground/src/createUI.ts b/packages/playground/src/createUI.ts index 006285249381..4ce3fee989d4 100644 --- a/packages/playground/src/createUI.ts +++ b/packages/playground/src/createUI.ts @@ -1,9 +1,29 @@ export interface UI { showModal: (message: string, subtitle?: string, buttons?: any) => void + flashInfo: (message: string) => void } export const createUI = (): UI => { return { + flashInfo: (message: string) => { + let flashBG = document.getElementById('flash-bg') + if (flashBG) { + flashBG.parentElement?.removeChild(flashBG) + } + + flashBG = document.createElement('div') + flashBG.id = 'flash-bg' + + const p = document.createElement('p') + p.textContent = message + flashBG.appendChild(p) + document.body.appendChild(flashBG) + + setTimeout(() => { + flashBG?.parentElement?.removeChild(flashBG) + }, 1000) + }, + showModal: (code: string, subtitle?: string, links?: any) => { document.querySelectorAll('.navbar-sub li.open').forEach(i => i.classList.remove('open')) diff --git a/packages/playground/src/getExample.ts b/packages/playground/src/getExample.ts index 4f9c5117e502..47a03561ad53 100644 --- a/packages/playground/src/getExample.ts +++ b/packages/playground/src/getExample.ts @@ -29,6 +29,9 @@ export const getExampleSourceCode = async (prefix: string, lang: string, example .trim() } + // @ts-ignore + window.appInsights.trackEvent({ name: 'Read Playground Example', properties: { id: exampleID, lang } }) + return { example, code, diff --git a/packages/playground/src/index.ts b/packages/playground/src/index.ts index 5123cb48c4d3..19c5c1ecc4ea 100644 --- a/packages/playground/src/index.ts +++ b/packages/playground/src/index.ts @@ -100,7 +100,6 @@ export const setupPlayground = ( return plugins[tabs.indexOf(selectedTab)] } - console.log(i) const initialPlugins = defaultPluginFactories.map(f => f(i)) initialPlugins.forEach(p => registerPlugin(p)) @@ -143,6 +142,8 @@ export const setupPlayground = ( // When any compiler flags are changed, trigger a potential change to the URL sandbox.setDidUpdateCompilerSettings(() => { playgroundDebouncedMainFunction() + // @ts-ignore + window.appInsights.trackEvent({ name: 'Compiler Settings changed' }) const model = sandbox.editor.getModel() const plugin = currentPlugin() @@ -159,7 +160,7 @@ export const setupPlayground = ( // Add the versions to the dropdown const versionsMenu = document.querySelectorAll('#versions > ul').item(0) - const allVersions = ['3.8.0-beta', ...sandbox.supportedVersions] + const allVersions = ['3.8.0-beta', ...sandbox.supportedVersions, 'Nightly'] allVersions.forEach((v: string) => { const li = document.createElement('li') const a = document.createElement('a') @@ -169,7 +170,9 @@ export const setupPlayground = ( li.onclick = () => { const currentURL = sandbox.getURLQueryWithCompilerOptions(sandbox) const params = new URLSearchParams(currentURL.split('#')[0]) - params.set('ts', v) + const version = v === 'Nightly' ? 'next' : v + params.set('ts', version) + const hash = document.location.hash.length ? document.location.hash : '' const newURL = `${document.location.protocol}//${document.location.host}${document.location.pathname}?${params}${hash}` @@ -196,7 +199,7 @@ export const setupPlayground = ( .getElementsByTagName('ul') .item(0)! - // SEt exact height and widths for the popovers for the main playground navigation + // Set exact height and widths for the popovers for the main playground navigation const isPlaygroundSubmenu = !!a.closest('nav') if (isPlaygroundSubmenu) { const playgroundContainer = document.getElementById('playground-container')! @@ -209,12 +212,43 @@ export const setupPlayground = ( } }) + window.addEventListener( + 'keydown', + (event: KeyboardEvent) => { + const S_KEY = 83 + if (event.keyCode == S_KEY && (event.metaKey || event.ctrlKey)) { + event.preventDefault() + + window.navigator.clipboard.writeText(location.href.toString()).then( + () => ui.flashInfo(i('play_export_clipboard')), + (e: any) => alert(e) + ) + } + + if ( + event.keyCode === 13 && + (event.metaKey || event.ctrlKey) && + event.target instanceof Node && + event.target === document.body + ) { + event.preventDefault() + const runButton = document.getElementById('run-button')! + runButton.onclick && runButton.onclick({} as any) + } + }, + false + ) + const runButton = document.getElementById('run-button')! runButton.onclick = () => { const run = sandbox.getRunnableJS() const runPlugin = plugins.find(p => p.id === 'logs')! activatePlugin(runPlugin, currentPlugin(), sandbox, tabBar, container) - runWithCustomLogs(run) + + runWithCustomLogs(run, i) + + const isJS = sandbox.config.useJavaScript + ui.flashInfo(i(isJS ? 'play_run_js' : 'play_run_ts')) } // Handle the close buttons on the examples @@ -348,6 +382,18 @@ export const setupPlayground = ( } }) + if (location.hash.startsWith('#show-examples')) { + setTimeout(() => { + document.getElementById('examples-button')?.click() + }, 100) + } + + if (location.hash.startsWith('#show-whatisnew')) { + setTimeout(() => { + document.getElementById('whatisnew-button')?.click() + }, 100) + } + return playground } diff --git a/packages/playground/src/sidebar/options.ts b/packages/playground/src/sidebar/options.ts index aabb29812d75..b7102f8a60f2 100644 --- a/packages/playground/src/sidebar/options.ts +++ b/packages/playground/src/sidebar/options.ts @@ -1,6 +1,3 @@ -// import React from "react" -// import { withPrefix } from "gatsby" - import { PlaygroundPlugin, PluginFactory } from '..' const pluginRegistry = [ @@ -35,6 +32,10 @@ const addCustomPlugin = (mod: string) => { const newPlugins = customPlugins() newPlugins.push(mod) localStorage.setItem('custom-plugins-playground', JSON.stringify(newPlugins)) + // @ts-ignore + window.appInsights && + // @ts-ignore + window.appInsights.trackEvent({ name: 'Added Custom Module', properties: { id: mod } }) } const customPlugins = (): string[] => { @@ -178,6 +179,10 @@ const createPlugin = (plugin: typeof pluginRegistry[0]) => { input.onchange = () => { announceWeNeedARestart() if (input.checked) { + // @ts-ignore + window.appInsights && + // @ts-ignore + window.appInsights.trackEvent({ name: 'Added Registry Plugin', properties: { id: key } }) localStorage.setItem(key, 'true') } else { localStorage.removeItem(key) diff --git a/packages/playground/src/sidebar/runtime.ts b/packages/playground/src/sidebar/runtime.ts index 58bf757f5fca..3f20a2a9cd97 100644 --- a/packages/playground/src/sidebar/runtime.ts +++ b/packages/playground/src/sidebar/runtime.ts @@ -33,7 +33,7 @@ export const runPlugin: PluginFactory = i => { return plugin } -export const runWithCustomLogs = (closure: Promise) => { +export const runWithCustomLogs = (closure: Promise, i: Function) => { const noLogs = document.getElementById('empty-message-container') if (noLogs) { noLogs.style.display = 'none' @@ -43,7 +43,8 @@ export const runWithCustomLogs = (closure: Promise) => { () => document.getElementById('log')!, () => document.getElementById('log-container')!, closure, - true + true, + i ) } @@ -53,7 +54,8 @@ function rewireLoggingToElement( eleLocator: () => Element, eleOverflowLocator: () => Element, closure: Promise, - autoScroll: boolean + autoScroll: boolean, + i: Function ) { fixLoggingFunc('log', 'LOG') fixLoggingFunc('debug', 'DBG') @@ -62,7 +64,12 @@ function rewireLoggingToElement( fixLoggingFunc('info', 'INF') closure.then(js => { - eval(js) + try { + eval(js) + } catch (error) { + console.error(i('play_run_js_fail')) + console.error(error) + } allLogs = allLogs + '
' diff --git a/packages/sandbox/src/compilerOptions.ts b/packages/sandbox/src/compilerOptions.ts index 2746b0854f5a..53e7a99e6bc5 100644 --- a/packages/sandbox/src/compilerOptions.ts +++ b/packages/sandbox/src/compilerOptions.ts @@ -110,6 +110,7 @@ export const getURLQueryWithCompilerOptions = (sandbox: any, paramOverrides?: an // Support sending the selection const s = sandbox.editor.getSelection() + // TODO: when it's full if ( (s && s.selectionStartLineNumber !== s.positionLineNumber) || (s && s.selectionStartColumn !== s.positionColumn) @@ -118,6 +119,11 @@ export const getURLQueryWithCompilerOptions = (sandbox: any, paramOverrides?: an urlParams['ssc'] = s.selectionStartColumn urlParams['pln'] = s.positionLineNumber urlParams['pc'] = s.positionColumn + } else { + urlParams['ssl'] = undefined + urlParams['ssc'] = undefined + urlParams['pln'] = undefined + urlParams['pc'] = undefined } if (sandbox.config.useJavaScript) urlParams['useJavaScript'] = true diff --git a/packages/typescriptlang-org/src/components/AppInsights.tsx b/packages/typescriptlang-org/src/components/AppInsights.tsx new file mode 100644 index 000000000000..30535a634e60 --- /dev/null +++ b/packages/typescriptlang-org/src/components/AppInsights.tsx @@ -0,0 +1,34 @@ +import React, { useEffect } from "react" + +/** + * Sets up the App Insights analytics, docs: https://github.com/Microsoft/ApplicationInsights-JS + * Mutates window to add window.appInsights + */ +export const AppInsights = () => { + useEffect(() => { + var sdkInstance = "appInsightsSDK"; + window[sdkInstance] = "appInsights"; + const config = { + instrumentationKey: "78a8fb52-a225-4c66-ac08-92fad1c1ade1", + // loggingLevelConsole: 1 + } + + // @ts-ignore + var aiName = window[sdkInstance], aisdk = window[aiName] || function (e) { function n(e) { t[e] = function () { var n = arguments; t.queue.push(function () { t[e].apply(t, n) }) } } var t = { config: e }; t.initialize = !0; var i = document, a = window; setTimeout(function () { var n = i.createElement("script"); n.async = true; n.src = e.url || "https://az416426.vo.msecnd.net/scripts/b/ai.2.min.js", i.getElementsByTagName("script")[0].parentNode.appendChild(n) }); try { t.cookie = i.cookie } catch (e) { } t.queue = [], t.version = 2; for (var r = ["Event", "PageView", "Exception", "Trace", "DependencyData", "Metric", "PageViewPerformance"]; r.length;)n("track" + r.pop()); n("startTrackPage"), n("stopTrackPage"); var s = "Track" + r[0]; if (n("start" + s), n("stop" + s), n("setAuthenticatedUserContext"), n("clearAuthenticatedUserContext"), n("flush"), !(!0 === e.disableExceptionTracking || e.extensionConfig && e.extensionConfig.ApplicationInsightsAnalytics && !0 === e.extensionConfig.ApplicationInsightsAnalytics.disableExceptionTracking)) { n("_" + (r = "onerror")); var o = a[r]; a[r] = function (e, n, i, a, s) { var c = o && o(e, n, i, a, s); return !0 !== c && t["_" + r]({ message: e, url: n, lineNumber: i, columnNumber: a, error: s }), c }, e.autoExceptionInstrumented = !0 } return t }(config); + window[aiName] = aisdk + + // @ts-ignore + if (aisdk.queue && 0 === aisdk.queue.length) { + const locationWithoutPlaygroundCode = document.location.href.split("#code")[0].split("#src")[0] + const referrerWithoutPlaygroundCode = document.referrer && document.referrer.split("#code")[0].split("#src")[0] + // @ts-ignore + aisdk.trackPageView({ uri: locationWithoutPlaygroundCode, refUri: referrerWithoutPlaygroundCode }); + } + }) + + return ( + <> +
+ + ) +} diff --git a/packages/typescriptlang-org/src/components/layout.tsx b/packages/typescriptlang-org/src/components/layout.tsx index f4d5b812a928..0a7bc3ce7515 100644 --- a/packages/typescriptlang-org/src/components/layout.tsx +++ b/packages/typescriptlang-org/src/components/layout.tsx @@ -3,6 +3,7 @@ import { SiteNav, Props } from "./layout/TopNav" import { SiteFooter } from "./layout/SiteFooter" import { SeoProps, HeadSEO } from "./HeadSEO"; import "./layout/main.scss" +import { AppInsights } from "./AppInsights"; type LayoutProps = SeoProps & Props & { children: any @@ -18,6 +19,7 @@ export const Layout = (props: LayoutProps) => {
{props.children}
+ ) } diff --git a/packages/typescriptlang-org/src/copy/en/playground.ts b/packages/typescriptlang-org/src/copy/en/playground.ts index 1f7fb2464bf3..dddd7bfe5877 100644 --- a/packages/typescriptlang-org/src/copy/en/playground.ts +++ b/packages/typescriptlang-org/src/copy/en/playground.ts @@ -40,6 +40,10 @@ export const playCopy = { play_export_tsast: "Open in TypeScript AST Viewer", play_export_sandbox: "Open in CodeSandbox", play_export_stackblitz: "Open in StackBlitz", + play_export_clipboard: "URL copied to clipboard", + play_run_js: "Executed JavaScript", + play_run_ts: "Executed transpiled TypeScript", + play_run_js_fail: "Executed JavaScript Failed:", play_default_code_sample: `// Welcome to the TypeScript Playground, this is a website // which gives you a chance to write, share and learn TypeScript. diff --git a/packages/typescriptlang-org/src/templates/play.scss b/packages/typescriptlang-org/src/templates/play.scss index c18f3f3fa94f..8c9d4c2f45ff 100644 --- a/packages/typescriptlang-org/src/templates/play.scss +++ b/packages/typescriptlang-org/src/templates/play.scss @@ -667,3 +667,32 @@ input.good { opacity: 0.5; } } + +#flash-bg { + top: 0; + left: 0; + right: 0; + bottom: 0; + position: fixed; + z-index: 42; + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; + + p { + background-color: rgba(0, 0, 0, 0.8); + color: white; + padding: 20px; + font-size: 1.5rem; + + border-radius: 1em; + padding: 0.5em 1.5em; + + color: white; + transition: opacity 0.1s ease-in-out; + + /* help Safari with blurred text */ + transform: translateZ(0); + } +} diff --git a/packages/typescriptlang-org/src/templates/play.tsx b/packages/typescriptlang-org/src/templates/play.tsx index ae2aef173019..034b42f54040 100644 --- a/packages/typescriptlang-org/src/templates/play.tsx +++ b/packages/typescriptlang-org/src/templates/play.tsx @@ -137,7 +137,7 @@ const Play = (props: Props) => {
  • - +