Skip to content

Commit f594d17

Browse files
author
Orta
authored
Merge pull request #223 from microsoft/playgorund-example-pages
Adds analytics to the playground, and nightly, and keyboard shortcuts
2 parents bcdaa7c + c1b5a58 commit f594d17

File tree

11 files changed

+170
-14
lines changed

11 files changed

+170
-14
lines changed

packages/playground/src/createUI.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,29 @@
11
export interface UI {
22
showModal: (message: string, subtitle?: string, buttons?: any) => void
3+
flashInfo: (message: string) => void
34
}
45

56
export const createUI = (): UI => {
67
return {
8+
flashInfo: (message: string) => {
9+
let flashBG = document.getElementById('flash-bg')
10+
if (flashBG) {
11+
flashBG.parentElement?.removeChild(flashBG)
12+
}
13+
14+
flashBG = document.createElement('div')
15+
flashBG.id = 'flash-bg'
16+
17+
const p = document.createElement('p')
18+
p.textContent = message
19+
flashBG.appendChild(p)
20+
document.body.appendChild(flashBG)
21+
22+
setTimeout(() => {
23+
flashBG?.parentElement?.removeChild(flashBG)
24+
}, 1000)
25+
},
26+
727
showModal: (code: string, subtitle?: string, links?: any) => {
828
document.querySelectorAll('.navbar-sub li.open').forEach(i => i.classList.remove('open'))
929

packages/playground/src/getExample.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ export const getExampleSourceCode = async (prefix: string, lang: string, example
2929
.trim()
3030
}
3131

32+
// @ts-ignore
33+
window.appInsights.trackEvent({ name: 'Read Playground Example', properties: { id: exampleID, lang } })
34+
3235
return {
3336
example,
3437
code,

packages/playground/src/index.ts

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,6 @@ export const setupPlayground = (
100100
return plugins[tabs.indexOf(selectedTab)]
101101
}
102102

103-
console.log(i)
104103
const initialPlugins = defaultPluginFactories.map(f => f(i))
105104
initialPlugins.forEach(p => registerPlugin(p))
106105

@@ -143,6 +142,8 @@ export const setupPlayground = (
143142
// When any compiler flags are changed, trigger a potential change to the URL
144143
sandbox.setDidUpdateCompilerSettings(() => {
145144
playgroundDebouncedMainFunction()
145+
// @ts-ignore
146+
window.appInsights.trackEvent({ name: 'Compiler Settings changed' })
146147

147148
const model = sandbox.editor.getModel()
148149
const plugin = currentPlugin()
@@ -159,7 +160,7 @@ export const setupPlayground = (
159160

160161
// Add the versions to the dropdown
161162
const versionsMenu = document.querySelectorAll('#versions > ul').item(0)
162-
const allVersions = ['3.8.0-beta', ...sandbox.supportedVersions]
163+
const allVersions = ['3.8.0-beta', ...sandbox.supportedVersions, 'Nightly']
163164
allVersions.forEach((v: string) => {
164165
const li = document.createElement('li')
165166
const a = document.createElement('a')
@@ -169,7 +170,9 @@ export const setupPlayground = (
169170
li.onclick = () => {
170171
const currentURL = sandbox.getURLQueryWithCompilerOptions(sandbox)
171172
const params = new URLSearchParams(currentURL.split('#')[0])
172-
params.set('ts', v)
173+
const version = v === 'Nightly' ? 'next' : v
174+
params.set('ts', version)
175+
173176
const hash = document.location.hash.length ? document.location.hash : ''
174177
const newURL = `${document.location.protocol}//${document.location.host}${document.location.pathname}?${params}${hash}`
175178

@@ -196,7 +199,7 @@ export const setupPlayground = (
196199
.getElementsByTagName('ul')
197200
.item(0)!
198201

199-
// SEt exact height and widths for the popovers for the main playground navigation
202+
// Set exact height and widths for the popovers for the main playground navigation
200203
const isPlaygroundSubmenu = !!a.closest('nav')
201204
if (isPlaygroundSubmenu) {
202205
const playgroundContainer = document.getElementById('playground-container')!
@@ -209,12 +212,43 @@ export const setupPlayground = (
209212
}
210213
})
211214

215+
window.addEventListener(
216+
'keydown',
217+
(event: KeyboardEvent) => {
218+
const S_KEY = 83
219+
if (event.keyCode == S_KEY && (event.metaKey || event.ctrlKey)) {
220+
event.preventDefault()
221+
222+
window.navigator.clipboard.writeText(location.href.toString()).then(
223+
() => ui.flashInfo(i('play_export_clipboard')),
224+
(e: any) => alert(e)
225+
)
226+
}
227+
228+
if (
229+
event.keyCode === 13 &&
230+
(event.metaKey || event.ctrlKey) &&
231+
event.target instanceof Node &&
232+
event.target === document.body
233+
) {
234+
event.preventDefault()
235+
const runButton = document.getElementById('run-button')!
236+
runButton.onclick && runButton.onclick({} as any)
237+
}
238+
},
239+
false
240+
)
241+
212242
const runButton = document.getElementById('run-button')!
213243
runButton.onclick = () => {
214244
const run = sandbox.getRunnableJS()
215245
const runPlugin = plugins.find(p => p.id === 'logs')!
216246
activatePlugin(runPlugin, currentPlugin(), sandbox, tabBar, container)
217-
runWithCustomLogs(run)
247+
248+
runWithCustomLogs(run, i)
249+
250+
const isJS = sandbox.config.useJavaScript
251+
ui.flashInfo(i(isJS ? 'play_run_js' : 'play_run_ts'))
218252
}
219253

220254
// Handle the close buttons on the examples
@@ -348,6 +382,18 @@ export const setupPlayground = (
348382
}
349383
})
350384

385+
if (location.hash.startsWith('#show-examples')) {
386+
setTimeout(() => {
387+
document.getElementById('examples-button')?.click()
388+
}, 100)
389+
}
390+
391+
if (location.hash.startsWith('#show-whatisnew')) {
392+
setTimeout(() => {
393+
document.getElementById('whatisnew-button')?.click()
394+
}, 100)
395+
}
396+
351397
return playground
352398
}
353399

packages/playground/src/sidebar/options.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
// import React from "react"
2-
// import { withPrefix } from "gatsby"
3-
41
import { PlaygroundPlugin, PluginFactory } from '..'
52

63
const pluginRegistry = [
@@ -35,6 +32,10 @@ const addCustomPlugin = (mod: string) => {
3532
const newPlugins = customPlugins()
3633
newPlugins.push(mod)
3734
localStorage.setItem('custom-plugins-playground', JSON.stringify(newPlugins))
35+
// @ts-ignore
36+
window.appInsights &&
37+
// @ts-ignore
38+
window.appInsights.trackEvent({ name: 'Added Custom Module', properties: { id: mod } })
3839
}
3940

4041
const customPlugins = (): string[] => {
@@ -178,6 +179,10 @@ const createPlugin = (plugin: typeof pluginRegistry[0]) => {
178179
input.onchange = () => {
179180
announceWeNeedARestart()
180181
if (input.checked) {
182+
// @ts-ignore
183+
window.appInsights &&
184+
// @ts-ignore
185+
window.appInsights.trackEvent({ name: 'Added Registry Plugin', properties: { id: key } })
181186
localStorage.setItem(key, 'true')
182187
} else {
183188
localStorage.removeItem(key)

packages/playground/src/sidebar/runtime.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export const runPlugin: PluginFactory = i => {
3333
return plugin
3434
}
3535

36-
export const runWithCustomLogs = (closure: Promise<string>) => {
36+
export const runWithCustomLogs = (closure: Promise<string>, i: Function) => {
3737
const noLogs = document.getElementById('empty-message-container')
3838
if (noLogs) {
3939
noLogs.style.display = 'none'
@@ -43,7 +43,8 @@ export const runWithCustomLogs = (closure: Promise<string>) => {
4343
() => document.getElementById('log')!,
4444
() => document.getElementById('log-container')!,
4545
closure,
46-
true
46+
true,
47+
i
4748
)
4849
}
4950

@@ -53,7 +54,8 @@ function rewireLoggingToElement(
5354
eleLocator: () => Element,
5455
eleOverflowLocator: () => Element,
5556
closure: Promise<string>,
56-
autoScroll: boolean
57+
autoScroll: boolean,
58+
i: Function
5759
) {
5860
fixLoggingFunc('log', 'LOG')
5961
fixLoggingFunc('debug', 'DBG')
@@ -62,7 +64,12 @@ function rewireLoggingToElement(
6264
fixLoggingFunc('info', 'INF')
6365

6466
closure.then(js => {
65-
eval(js)
67+
try {
68+
eval(js)
69+
} catch (error) {
70+
console.error(i('play_run_js_fail'))
71+
console.error(error)
72+
}
6673

6774
allLogs = allLogs + '<hr />'
6875

packages/sandbox/src/compilerOptions.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export const getURLQueryWithCompilerOptions = (sandbox: any, paramOverrides?: an
110110

111111
// Support sending the selection
112112
const s = sandbox.editor.getSelection()
113+
// TODO: when it's full
113114
if (
114115
(s && s.selectionStartLineNumber !== s.positionLineNumber) ||
115116
(s && s.selectionStartColumn !== s.positionColumn)
@@ -118,6 +119,11 @@ export const getURLQueryWithCompilerOptions = (sandbox: any, paramOverrides?: an
118119
urlParams['ssc'] = s.selectionStartColumn
119120
urlParams['pln'] = s.positionLineNumber
120121
urlParams['pc'] = s.positionColumn
122+
} else {
123+
urlParams['ssl'] = undefined
124+
urlParams['ssc'] = undefined
125+
urlParams['pln'] = undefined
126+
urlParams['pc'] = undefined
121127
}
122128

123129
if (sandbox.config.useJavaScript) urlParams['useJavaScript'] = true
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React, { useEffect } from "react"
2+
3+
/**
4+
* Sets up the App Insights analytics, docs: https://github.com/Microsoft/ApplicationInsights-JS
5+
* Mutates window to add window.appInsights
6+
*/
7+
export const AppInsights = () => {
8+
useEffect(() => {
9+
var sdkInstance = "appInsightsSDK";
10+
window[sdkInstance] = "appInsights";
11+
const config = {
12+
instrumentationKey: "78a8fb52-a225-4c66-ac08-92fad1c1ade1",
13+
// loggingLevelConsole: 1
14+
}
15+
16+
// @ts-ignore
17+
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);
18+
window[aiName] = aisdk
19+
20+
// @ts-ignore
21+
if (aisdk.queue && 0 === aisdk.queue.length) {
22+
const locationWithoutPlaygroundCode = document.location.href.split("#code")[0].split("#src")[0]
23+
const referrerWithoutPlaygroundCode = document.referrer && document.referrer.split("#code")[0].split("#src")[0]
24+
// @ts-ignore
25+
aisdk.trackPageView({ uri: locationWithoutPlaygroundCode, refUri: referrerWithoutPlaygroundCode });
26+
}
27+
})
28+
29+
return (
30+
<>
31+
<div />
32+
</>
33+
)
34+
}

packages/typescriptlang-org/src/components/layout.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { SiteNav, Props } from "./layout/TopNav"
33
import { SiteFooter } from "./layout/SiteFooter"
44
import { SeoProps, HeadSEO } from "./HeadSEO";
55
import "./layout/main.scss"
6+
import { AppInsights } from "./AppInsights";
67

78
type LayoutProps = SeoProps & Props & {
89
children: any
@@ -18,6 +19,7 @@ export const Layout = (props: LayoutProps) => {
1819
<main>{props.children}</main>
1920
<SiteFooter />
2021
</div>
22+
<AppInsights />
2123
</>
2224
)
2325
}

packages/typescriptlang-org/src/copy/en/playground.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ export const playCopy = {
4040
play_export_tsast: "Open in TypeScript AST Viewer",
4141
play_export_sandbox: "Open in CodeSandbox",
4242
play_export_stackblitz: "Open in StackBlitz",
43+
play_export_clipboard: "URL copied to clipboard",
44+
play_run_js: "Executed JavaScript",
45+
play_run_ts: "Executed transpiled TypeScript",
46+
play_run_js_fail: "Executed JavaScript Failed:",
4347
play_default_code_sample: `// Welcome to the TypeScript Playground, this is a website
4448
// which gives you a chance to write, share and learn TypeScript.
4549

packages/typescriptlang-org/src/templates/play.scss

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,3 +667,32 @@ input.good {
667667
opacity: 0.5;
668668
}
669669
}
670+
671+
#flash-bg {
672+
top: 0;
673+
left: 0;
674+
right: 0;
675+
bottom: 0;
676+
position: fixed;
677+
z-index: 42;
678+
display: flex;
679+
justify-content: center;
680+
align-items: center;
681+
pointer-events: none;
682+
683+
p {
684+
background-color: rgba(0, 0, 0, 0.8);
685+
color: white;
686+
padding: 20px;
687+
font-size: 1.5rem;
688+
689+
border-radius: 1em;
690+
padding: 0.5em 1.5em;
691+
692+
color: white;
693+
transition: opacity 0.1s ease-in-out;
694+
695+
/* help Safari with blurred text */
696+
transform: translateZ(0);
697+
}
698+
}

packages/typescriptlang-org/src/templates/play.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,15 @@ const Play = (props: Props) => {
137137
</li>
138138

139139
<li className="dropdown">
140-
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{i("play_subnav_examples")} <span className="caret"></span></a>
140+
<a href="#" id="whatisnew-button" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{i("play_subnav_examples")} <span className="caret"></span></a>
141141
<ul className="examples-dropdown" id="examples" >
142142
<button className="examples-close">{i("play_subnav_examples_close")}</button>
143143
<RenderExamples defaultSection="JavaScript" sections={["JavaScript", "TypeScript"]} examples={props.pageContext.examplesTOC} locale={props.pageContext.lang} />
144144
</ul>
145145
</li>
146146

147147
<li className="dropdown">
148-
<a href="#" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{i("play_subnav_whatsnew")} <span className="caret"></span></a>
148+
<a href="#" id="examples-button" className="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">{i("play_subnav_whatsnew")} <span className="caret"></span></a>
149149
<ul className="examples-dropdown" id="whatisnew">
150150
<button className="examples-close">{i("play_subnav_examples_close")}</button>
151151
<RenderExamples defaultSection="3.8" sections={["3.8", "3.7", "Playground"]} examples={props.pageContext.examplesTOC} locale={props.pageContext.lang} />

0 commit comments

Comments
 (0)