📄 editor.js
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 72 |
📊 Variables & Constants | 102 |
⚡ Async/Await Patterns | 12 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 manual/examples/resources/editor.js
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
lessonHelperScriptRE |
RegExp |
let/var | /<script src="[^"]+lessons-helper\.js"><\/script>/ |
✗ |
webglDebugHelperScriptRE |
RegExp |
let/var | /<script src="[^"]+webgl-debug-helper\.js"><\/script>/ |
✗ |
query |
{} |
let/var | {} |
✗ |
url |
URL |
let/var | new URL( path, baseUrl \|\| window.location.href ) |
✗ |
req |
Response |
let/var | await fetch( url ) |
✗ |
u |
URL |
let/var | new URL( url, window.location.href ) |
✗ |
prefix |
string |
let/var | u.origin + dirname( u.pathname ) |
✗ |
cssUrlRE1 |
RegExp |
let/var | /(url\(')(.*?)('\))/g |
✗ |
cssUrlRE2 |
RegExp |
let/var | /(url\()(.*?)(\))/g |
✗ |
g |
Globals |
let/var | { html: '', } |
✗ |
htmlParts |
{ [x: string]: HTMLPart; } |
let/var | { js: { language: 'javascript', sources: [], }, css: { language: 'css', sourc... |
✗ |
u |
URL |
let/var | new URL( url, window.location.href ) |
✗ |
url |
URL |
let/var | new URL( href, window.location.href ) |
✗ |
info |
HTMLPart |
let/var | htmlParts[ name ] |
✗ |
part |
string |
let/var | '' |
✗ |
indent |
string |
let/var | '' |
✗ |
currIndent |
string |
let/var | indent |
✗ |
source |
string |
let/var | await getHTML( url ) |
✗ |
parentScriptInfo |
any |
let/var | scriptInfos[ baseUrl ] |
✗ |
workerRE |
RegExp |
let/var | /(new\s+Worker\s*\(\s*)('\|")(.*?)('\|")/g |
✗ |
importScriptsRE |
RegExp |
let/var | /(importScripts\s*\(\s*)('\|")(.*?)('\|")/g |
✗ |
importRE |
RegExp |
let/var | /(import.*?)(?!'three')('\|")(.*?)('\|")/g |
✗ |
newScripts |
any[] |
let/var | [] |
✗ |
slashRE |
RegExp |
let/var | /\/manual\/examples\/[^/]+$/ |
✗ |
styleRE |
RegExp |
let/var | /<style>([^]*?)<\/style>/i |
✗ |
titleRE |
RegExp |
let/var | /<title>([^]*?)<\/title>/i |
✗ |
bodyRE |
RegExp |
let/var | /<body>([^]*?)<\/body>/i |
✗ |
inlineScriptRE |
RegExp |
let/var | /<script>([^]*?)<\/script>/i |
✗ |
inlineModuleScriptRE |
RegExp |
let/var | /<script type="module">([^]*?)<\/script>/i |
✗ |
externalScriptRE |
RegExp |
let/var | /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\... |
✗ |
dataScriptRE |
RegExp |
let/var | /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([... |
✗ |
cssLinkRE |
RegExp |
let/var | /<link ([^>]+?)>/g |
✗ |
isCSSLinkRE |
RegExp |
let/var | /type="text\/css"\|rel="stylesheet"/ |
✗ |
hrefRE |
RegExp |
let/var | /href="([^"]+)"/ |
✗ |
obj |
{ html: any; } |
let/var | { html: html } |
✗ |
rootScript |
string |
let/var | getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) \|\| getHTMLPart... |
✗ |
scriptInfos |
{ [x: string]: SourceInfo; } |
let/var | {} |
✗ |
kScript |
"script" |
let/var | 'script' |
✗ |
scripts |
any[] |
let/var | [] |
✗ |
importMapRE |
RegExp |
let/var | /type\s*=["']importmap["']/ |
✗ |
dataScripts |
any[] |
let/var | [] |
✗ |
imports |
any |
let/var | imap.imports |
✗ |
links |
string |
let/var | '' |
✗ |
html |
any |
let/var | *not shown* |
✗ |
blob |
Blob |
let/var | new Blob( [ source ], { type: 'application/javascript' } ) |
✗ |
blobGeneration |
number |
let/var | 0 |
✗ |
text |
any |
let/var | scriptInfo.source |
✗ |
extra |
string |
let/var | `self.lessonSettings = ${JSON.stringify( lessonSettings )}; import '${dirname... |
✗ |
prefix |
any |
let/var | dname |
✗ |
source |
any |
let/var | g.html |
✗ |
blob |
Blob |
let/var | new Blob( [ source ], { type: 'text/html' } ) |
✗ |
scripts |
any[] |
let/var | [] |
✗ |
text |
any |
let/var | scriptInfo.source |
✗ |
mainScriptInfo |
any |
let/var | scripts[ scripts.length - 1 ] |
✗ |
workerScriptInfo |
any |
let/var | scripts[ scripts.length - 2 ] |
✗ |
workerName |
any |
let/var | workerScriptInfo.name |
✗ |
init |
"\n\n\n\n// ------\n// Creates Blobs ... |
let/var | ` // ------ // Creates Blobs for the Scripts so things can be self contained ... |
✗ |
comment |
string |
let/var | // ${g.title} // from ${g.url} |
✗ |
code |
any |
let/var | await fixJSForCodeSite( scripts.js ) |
✗ |
html |
any |
let/var | await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) |
✗ |
pen |
{ title: any; description: string; ta... |
let/var | { title: g.title, description: 'from: ' + g.url, tags: lessonEditorSettings.t... |
✗ |
comment |
string |
let/var | // ${g.title} // from ${g.url} |
✗ |
code |
any |
let/var | await fixJSForCodeSite( scripts.js ) |
✗ |
html |
any |
let/var | await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) |
✗ |
comment |
string |
let/var | // ${g.title} // from ${g.url} |
✗ |
code |
any |
let/var | await fixJSForCodeSite( scripts.js ) |
✗ |
html |
any |
let/var | await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) |
✗ |
gist |
{ name: any; settings: {}; files: { n... |
let/var | { name: g.title, settings: {}, files: [ { name: 'index.html', content: script... |
✗ |
comment |
string |
let/var | // ${g.title} // from ${g.url} |
✗ |
code |
any |
let/var | await fixJSForCodeSite( scripts.js ) |
✗ |
html |
any |
let/var | await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) |
✗ |
mainHTML |
string |
let/var | scripts.html + html |
✗ |
mainJS |
string |
let/var | comment + code |
✗ |
mainCSS |
any |
let/var | htmlParts.css.sources[ 0 ].source |
✗ |
text |
string |
let/var | asModule ? <!-- begin snippet: js hide: false console: true babel: false --...` |
✗ |
keyStrBase64 |
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghij... |
let/var | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' |
✗ |
i |
any |
let/var | *not shown* |
✗ |
value |
any |
let/var | *not shown* |
✗ |
context_dictionary |
{} |
let/var | {} |
✗ |
context_dictionaryToCreate |
{} |
let/var | {} |
✗ |
context_c |
string |
let/var | '' |
✗ |
context_wc |
string |
let/var | '' |
✗ |
context_w |
string |
let/var | '' |
✗ |
context_enlargeIn |
number |
let/var | 2 |
✗ |
context_dictSize |
number |
let/var | 3 |
✗ |
context_numBits |
number |
let/var | 2 |
✗ |
context_data |
any[] |
let/var | [] |
✗ |
context_data_val |
number |
let/var | 0 |
✗ |
context_data_position |
number |
let/var | 0 |
✗ |
ii |
any |
let/var | *not shown* |
✗ |
comment |
string |
let/var | // ${g.title} // from ${g.url} |
✗ |
code |
any |
let/var | await fixJSForCodeSite( mainScript.text ) |
✗ |
html |
any |
let/var | await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) |
✗ |
selected |
boolean |
let/var | i === ndx |
✗ |
info |
HTMLPart |
let/var | htmlParts[ type ] |
✗ |
numParts |
any |
let/var | parts.length |
✗ |
frame |
any |
let/var | childWindow.frameElement |
✗ |
pressed |
boolean |
let/var | pressedButton === info.button |
✗ |
origUrl |
any |
let/var | url |
✗ |
actualLineNo |
any |
let/var | lineNo |
✗ |
editor |
any |
let/var | htmlParts.js.editors[ editorNdx ].editor |
✗ |
html |
any |
let/var | *not shown* |
✗ |
Async/Await Patterns¶
Type | Function | Await Expressions | Promise Chains |
---|---|---|---|
async-function | getHTML |
fetch( url ), req.text() | none |
async-function | getScript |
getHTML( url ), getWorkerScripts( fixedSource, url, scriptInfos ) | none |
async-function | getWorkerScripts |
Promise.all( newScripts.map( ( url ) => { |
return getScript( url, scriptInfos );
} ) ) | Promise.all |
| async-function | parseHTML
| getWorkerScripts( rootScript, fqURL, scriptInfos ) | none |
| async-function | main
| getHTML( query.url ), parseHTML( query.url, html ) | none |
| async-function | fixHTMLForCodeSite
| none | none |
| async-function | openInCodepen
| fixJSForCodeSite( scripts.js ), fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) | none |
| async-function | openInJSFiddle
| fixJSForCodeSite( scripts.js ), fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) | none |
| async-function | openInJSGist
| fixJSForCodeSite( scripts.js ), fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) | none |
| async-function | openInStackOverflow
| fixJSForCodeSite( scripts.js ), fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) | none |
| async-function | openInCodeSandbox
| fixJSForCodeSite( mainScript.text ), fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source ) | none |
| async-function | runAsBlob
| getHTML( query.url ), parseHTML( query.url, html ) | none |
Functions¶
getQuery(s: any): {}
¶
Parameters:
s
any
Returns: {}
Calls:
s.substring
s.split( '&' ).forEach
pair.split( '=' ).map
Codee.replace`
function getQuery( s ) {
s = s === undefined ? window.location.search : s;
if ( s[ 0 ] === '?' ) {
s = s.substring( 1 );
}
const query = {};
s.split( '&' ).forEach( function ( pair ) {
const parts = pair.split( '=' ).map( decodeURIComponent );
query[ parts[ 0 ] ] = parts[ 1 ];
} );
return query;
}
getSearch(url: any): {}
¶
Parameters:
url
any
Returns: {}
Calls:
url.indexOf
getQuery
url.substring
Internal Comments:
Code>
function getSearch( url ) {
// yea I know this is not perfect but whatever
const s = url.indexOf( '?' );
return s < 0 ? {} : getQuery( url.substring( s ) );
}
### `makeFQ(match: any, prefix: any, url: any, suffix: any): string`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`url`** `any`
- **`suffix`** `any`
**Returns:** `string`
**Calls:**
- `addPrefix`
getFQUrl(path: any, baseUrl: any): string
¶
Parameters:
path
any
baseUrl
any
Returns: string
Codefix`
function getFQUrl( path, baseUrl ) {
const url = new URL( path, baseUrl || window.location.href );
return url.href;
}
- `addPrefix`
getHTML(url: any): Promise<string>
¶
Parameters:
url
any
Returns: Promise<string>
Calls:
fetch
req.text
getPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Calls:
dirname
Coderts.join`
- `url.toString`
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
function getPrefix( url ) {
const u = new URL( url, window.location.href );
const prefix = u.origin + dirname( u.pathname );
return prefix;
}
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
fixCSSLinks(url: any, source: any): any
¶
Parameters:
url
any
source
any
Returns: any
Calls:
getPrefix
url.indexOf
url.startsWith
addPrefix
source.replace
Coderts ).forEach`
- `fn`
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getQuery( s ) {
s = s === undefined ? window.location.search : s;
if ( s[ 0 ] === '?' ) {
s = s.substring( 1 );
}
const query = {};
s.split( '&' ).forEach( function ( pair ) {
const parts = pair.split( '=' ).map( decodeURIComponent );
query[ parts[ 0 ] ] = parts[ 1 ];
} );
return query;
}
getSearch(url: any): {}
¶
Parameters:
url
any
Returns: {}
Calls:
url.indexOf
getQuery
url.substring
Internal Comments:
Code>
function getSearch( url ) {
// yea I know this is not perfect but whatever
const s = url.indexOf( '?' );
return s < 0 ? {} : getQuery( url.substring( s ) );
}
### `makeFQ(match: any, prefix: any, url: any, suffix: any): string`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`url`** `any`
- **`suffix`** `any`
**Returns:** `string`
**Calls:**
- `addPrefix`
getFQUrl(path: any, baseUrl: any): string
¶
Parameters:
path
any
baseUrl
any
Returns: string
Codefix`
function getFQUrl( path, baseUrl ) {
const url = new URL( path, baseUrl || window.location.href );
return url.href;
}
- `addPrefix`
getHTML(url: any): Promise<string>
¶
Parameters:
url
any
Returns: Promise<string>
Calls:
fetch
req.text
getPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Calls:
dirname
Coderts.join`
- `url.toString`
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
function getPrefix( url ) {
const u = new URL( url, window.location.href );
const prefix = u.origin + dirname( u.pathname );
return prefix;
}
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
fixCSSLinks(url: any, source: any): any
¶
Parameters:
url
any
source
any
Returns: any
Calls:
getPrefix
url.indexOf
url.startsWith
addPrefix
source.replace
Coderts ).forEach`
- `fn`
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getSearch( url ) {
// yea I know this is not perfect but whatever
const s = url.indexOf( '?' );
return s < 0 ? {} : getQuery( url.substring( s ) );
}
getFQUrl(path: any, baseUrl: any): string
¶
Parameters:
path
any
baseUrl
any
Returns: string
Codefix`
function getFQUrl( path, baseUrl ) {
const url = new URL( path, baseUrl || window.location.href );
return url.href;
}
- `addPrefix`
getHTML(url: any): Promise<string>
¶
Parameters:
url
any
Returns: Promise<string>
Calls:
fetch
req.text
getPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Calls:
dirname
Coderts.join`
- `url.toString`
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
function getPrefix( url ) {
const u = new URL( url, window.location.href );
const prefix = u.origin + dirname( u.pathname );
return prefix;
}
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
fixCSSLinks(url: any, source: any): any
¶
Parameters:
url
any
source
any
Returns: any
Calls:
getPrefix
url.indexOf
url.startsWith
addPrefix
source.replace
Coderts ).forEach`
- `fn`
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getFQUrl( path, baseUrl ) {
const url = new URL( path, baseUrl || window.location.href );
return url.href;
}
getHTML(url: any): Promise<string>
¶
Parameters:
url
any
Returns: Promise<string>
Calls:
fetch
req.text
getPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Calls:
dirname
Coderts.join`
- `url.toString`
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
function getPrefix( url ) {
const u = new URL( url, window.location.href );
const prefix = u.origin + dirname( u.pathname );
return prefix;
}
**Internal Comments:**
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
fixCSSLinks(url: any, source: any): any
¶
Parameters:
url
any
source
any
Returns: any
Calls:
getPrefix
url.indexOf
url.startsWith
addPrefix
source.replace
Coderts ).forEach`
- `fn`
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
function getPrefix( url ) {
const u = new URL( url, window.location.href );
const prefix = u.origin + dirname( u.pathname );
return prefix;
}
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
fixCSSLinks(url: any, source: any): any
¶
Parameters:
url
any
source
any
Returns: any
Calls:
getPrefix
url.indexOf
url.startsWith
addPrefix
source.replace
Coderts ).forEach`
- `fn`
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function fixCSSLinks( url, source ) {
const cssUrlRE1 = /(url\(')(.*?)('\))/g;
const cssUrlRE2 = /(url\()(.*?)(\))/g;
const prefix = getPrefix( url );
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
function makeFQ( match, prefix, url, suffix ) {
return `${prefix}${addPrefix( url )}${suffix}`;
}
source = source.replace( cssUrlRE1, makeFQ );
source = source.replace( cssUrlRE2, makeFQ );
return source;
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
Codel.replace`
- `part.replace`
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
- `part.replace`
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ? `${prefix}/${url}` : url;
}
makeFQ(match: any, prefix: any, url: any, suffix: any): string
¶
Parameters:
match
any
prefix
any
url
any
suffix
any
Returns: string
Calls:
addPrefix
Codeap( ( line ) =>
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
getRootPrefix(url: any): string
¶
Parameters:
url
any
Returns: string
Code{currIndent}${line.trim()}`;
} ).join`
} ).join`
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
removeDotDotSlash(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
url.pathname.split
parts.indexOf
parts.splice
parts.join
url.toString
Internal Comments:
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail. (x2)
Code*
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function removeDotDotSlash( href ) {
// assumes a well formed URL. In other words: 'https://..//foo.html" is a bad URL and this code would fail.
const url = new URL( href, window.location.href );
const parts = url.pathname.split( '/' );
for ( ;; ) {
const dotDotNdx = parts.indexOf( '..' );
if ( dotDotNdx < 0 ) {
break;
}
parts.splice( dotDotNdx - 1, 2 );
}
url.pathname = parts.join( '/' );
return url.toString();
}
forEachHTMLPart(fn: any): void
¶
Parameters:
fn
any
Returns: void
Calls:
Object.keys( htmlParts ).forEach
fn
Code}`
**Returns:** `Promise<{ text: any; scriptInfos: {}; }>
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
**Calls:**
- `getFQUrl`
- `slashRE.test`
- `match.toString`
- `prefix.indexOf`
- `newScripts.push`
- `parentScriptInfo.deps.push`
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `text.replace`
- `Promise.all`
- `newScripts.map`
- `getScript`
**Internal Comments:**
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function forEachHTMLPart( fn ) {
Object.keys( htmlParts ).forEach( function ( name, ndx ) {
const info = htmlParts[ name ];
fn( info, ndx, name );
} );
}
getHTMLPart(re: any, obj: any, tag: any): string
¶
Parameters:
re
any
obj
any
tag
any
Returns: string
Calls:
obj.html.replace
part.replace
Code
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getHTMLPart( re, obj, tag ) {
let part = '';
obj.html = obj.html.replace( re, function ( p0, p1 ) {
part = p1;
return tag;
} );
return part.replace( /\s*/, '' );
}
formatCSS(css: any): any
¶
Parameters:
css
any
Returns: any
Calls:
- `css.split( '\n' ).map( ( line ) => {
let currIndent = indent; if ( line.includes( '{' ) ) { indent = indent + ' '; } else if ( line.includes( '}' ) ) { indent = indent.substring( 0, indent.length - 2 ); currIndent = indent; } return `${currIndent}${line.trim()}`; } ).join`
Codedule(match: any, prefix: any, quote: any, url: any): any`
**Parameters:**
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
- **`match`** `any`
- **`prefix`** `any`
- **`quote`** `any`
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.startsWith`
- `url.includes`
- `replaceWithUUID`
- `match.toString`
**Internal Comments:**
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function formatCSS( css ) {
let indent = '';
return css.split( '\n' ).map( ( line ) => {
let currIndent = indent;
if ( line.includes( '{' ) ) {
indent = indent + ' ';
} else if ( line.includes( '}' ) ) {
indent = indent.substring( 0, indent.length - 2 );
currIndent = indent;
}
return `${currIndent}${line.trim()}`;
} ).join( '\n' );
}
getScript(url: any, scriptInfos: any): Promise<void>
¶
Parameters:
url
any
scriptInfos
any
Returns: Promise<void>
Calls:
getHTML
fixSourceLinks
getWorkerScripts
Internal Comments:
Code>
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
### `addSource(type: any, name: any, source: any, scriptInfo: any): void`
**Parameters:**
- **`type`** `any`
- **`name`** `any`
- **`source`** `any`
- **`scriptInfo`** `any`
**Returns:** `void`
**Calls:**
- `htmlParts[ type ].sources.push`
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function getScript( url, scriptInfos ) {
// check it's an example script, not some other lib
if ( ! scriptInfos[ url ].source ) {
const source = await getHTML( url );
const fixedSource = fixSourceLinks( url, source );
const { text } = await getWorkerScripts( fixedSource, url, scriptInfos );
scriptInfos[ url ].source = text;
}
}
getWorkerScripts(text: any, baseUrl: any, scriptInfos: {}): Promise<{ text: any; scriptInfos: {}; }>
¶
JSDoc:
/**
* @typedef {Object} ScriptInfo
* @property {string} fqURL The original fully qualified URL
* @property {ScriptInfo[]} deps Array of other ScriptInfos this is script dependant on
* @property {boolean} isWorker True if this script came from `new Worker('someurl')` vs `import` or `importScripts`
* @property {string} blobUrl The blobUrl for this script if one has been made
* @property {number} blobGenerationId Used to not visit things twice while recursing.
* @property {string} source The source as extracted. Updated from editor by getSourcesFromEditor
* @property {string} munged The source after urls have been replaced with blob urls etc... (the text send to new Blob)
*/
Parameters:
text
any
baseUrl
any
scriptInfos
{}
Returns: Promise<{ text: any; scriptInfos: {}; }>
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
url.startsWith
url.includes
replaceWithUUID
text.replace
Promise.all
newScripts.map
getScript
Internal Comments:
Code`url`** `any`
- **`html`** `any`
**Returns:** `Promise
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
- **`url`** `any`
- **`html`** `any`
**Returns:** `Promise
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function getWorkerScripts( text, baseUrl, scriptInfos = {} ) {
const parentScriptInfo = scriptInfos[ baseUrl ];
const workerRE = /(new\s+Worker\s*\(\s*)('|")(.*?)('|")/g;
const importScriptsRE = /(importScripts\s*\(\s*)('|")(.*?)('|")/g;
const importRE = /(import.*?)(?!'three')('|")(.*?)('|")/g;
const newScripts = [];
const slashRE = /\/manual\/examples\/[^/]+$/;
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
text = text.replace( workerRE, replaceWithUUID );
text = text.replace( importScriptsRE, replaceWithUUID );
text = text.replace( importRE, replaceWithUUIDModule );
await Promise.all( newScripts.map( ( url ) => {
return getScript( url, scriptInfos );
} ) );
return { text, scriptInfos };
}
replaceWithUUID(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
getFQUrl
slashRE.test
match.toString
prefix.indexOf
newScripts.push
parentScriptInfo.deps.push
Code`removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
- `url.indexOf`
- `url.startsWith`
- `addCorrectPrefix`
- `importMapRE.test`
- `JSON.parse`
- `addPrefix`
- `JSON.stringify`
- `dataScripts.push`
- `dataScripts.join`
- `scripts.join`
- `html.indexOf`
- `extraHTMLParsing`
- `isCSSLinkRE.test`
- `hrefRE.exec`
**Internal Comments:**
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
function replaceWithUUID( match, prefix, quote, url ) {
const fqURL = getFQUrl( url, baseUrl );
if ( ! slashRE.test( fqURL ) ) {
return match.toString();
}
if ( ! scriptInfos[ url ] ) {
scriptInfos[ fqURL ] = {
fqURL,
deps: [],
isWorker: prefix.indexOf( 'Worker' ) >= 0,
};
newScripts.push( fqURL );
}
parentScriptInfo.deps.push( scriptInfos[ fqURL ] );
return `${prefix}${quote}${fqURL}${quote}`;
}
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
replaceWithUUIDModule(match: any, prefix: any, quote: any, url: any): any
¶
Parameters:
match
any
prefix
any
quote
any
url
any
Returns: any
Calls:
url.startsWith
url.includes
replaceWithUUID
match.toString
Internal Comments:
Codehref: any): string`
**Parameters:**
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
- **`href`** `any`
**Returns:** `string`
**Calls:**
- `href.startsWith`
- `removeDotDotSlash`
- `( `${prefix}/${href}` ).replace`
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function replaceWithUUIDModule( match, prefix, quote, url ) {
// modules are either relative, fully qualified, or a module name
// Skip it if it's a module name
return ( url.startsWith( '.' ) || url.includes( '://' ) )
? replaceWithUUID( match, prefix, quote, url )
: match.toString();
}
addSource(type: any, name: any, source: any, scriptInfo: any): void
¶
Parameters:
type
any
name
any
source
any
scriptInfo
any
Returns: void
Calls:
htmlParts[ type ].sources.push
Code`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
- **`url`** `any`
**Returns:** `any`
**Calls:**
- `url.indexOf`
- `url.startsWith`
- `removeDotDotSlash`
- `addCorrectPrefix`
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function addSource( type, name, source, scriptInfo ) {
htmlParts[ type ].sources.push( { source, name, scriptInfo } );
}
safeStr(s: any): any
¶
Parameters:
s
any
Returns: any
Codee
parseHTML(url: any, html: any): Promise<void>
¶
Parameters:
url
any
html
any
Returns: Promise<void>
Calls:
fixSourceLinks
html.replace
addSource
formatCSS
fixCSSLinks
getHTMLPart
getFQUrl
getWorkerScripts
Object.entries
basename
titleRE.exec
scripts.push
safeStr
getPrefix
getRootPrefix
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
url.indexOf
url.startsWith
addCorrectPrefix
importMapRE.test
JSON.parse
addPrefix
JSON.stringify
dataScripts.push
dataScripts.join
scripts.join
html.indexOf
extraHTMLParsing
isCSSLinkRE.test
hrefRE.exec
Internal Comments:
/** @type Object<string, SourceInfo> */ (x2)
// add style section if there is non
// add hackedparams section. (x3)
// We need a way to pass parameters to a blob. Normally they'd be passed as (x3)
// query params but that only works in Firefox >:( (x3)
CodeokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
- `makeBlobURLForSourcesImpl`
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function parseHTML( url, html ) {
html = fixSourceLinks( url, html );
html = html.replace( /<div class="description">[^]*?<\/div>/, '' );
const styleRE = /<style>([^]*?)<\/style>/i;
const titleRE = /<title>([^]*?)<\/title>/i;
const bodyRE = /<body>([^]*?)<\/body>/i;
const inlineScriptRE = /<script>([^]*?)<\/script>/i;
const inlineModuleScriptRE = /<script type="module">([^]*?)<\/script>/i;
const externalScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script\s+([^>]*?)(type="module"\s+)?src\s*=\s*"(.*?)"(.*?)>\s*<\/script>/ig;
const dataScriptRE = /(<!--(?:(?!-->)[\s\S])*?-->\n){0,1}<script([^>]*?type="(?!module).*?".*?)>([^]*?)<\/script>/ig;
const cssLinkRE = /<link ([^>]+?)>/g;
const isCSSLinkRE = /type="text\/css"|rel="stylesheet"/;
const hrefRE = /href="([^"]+)"/;
const obj = { html: html };
addSource( 'css', 'css', formatCSS( fixCSSLinks( url, getHTMLPart( styleRE, obj, '<style>\n${css}</style>' ) ) ) );
addSource( 'html', 'html', getHTMLPart( bodyRE, obj, '<body>${html}</body>' ) );
const rootScript = getHTMLPart( inlineScriptRE, obj, '<script>${js}</script>' ) ||
getHTMLPart( inlineModuleScriptRE, obj, '<script type="module">${js}</script>' );
html = obj.html;
const fqURL = getFQUrl( url );
/** @type Object<string, SourceInfo> */
const scriptInfos = {};
g.rootScriptInfo = {
fqURL,
deps: [],
source: rootScript,
};
scriptInfos[ fqURL ] = g.rootScriptInfo;
const { text } = await getWorkerScripts( rootScript, fqURL, scriptInfos );
g.rootScriptInfo.source = text;
g.scriptInfos = scriptInfos;
for ( const [ fqURL, scriptInfo ] of Object.entries( scriptInfos ) ) {
addSource( 'js', basename( fqURL ), scriptInfo.source, scriptInfo );
}
const tm = titleRE.exec( html );
if ( tm ) {
g.title = tm[ 1 ];
}
const kScript = 'script';
const scripts = [];
html = html.replace( externalScriptRE, function ( p0, p1, p2, type, p3, p4 ) {
p1 = p1 || '';
scripts.push( `${p1}<${kScript} ${p2}${safeStr( type )}src="${p3}"${p4}></${kScript}>` );
return '';
} );
const prefix = getPrefix( url );
const rootPrefix = getRootPrefix( url );
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
const importMapRE = /type\s*=["']importmap["']/;
const dataScripts = [];
html = html.replace( dataScriptRE, function ( p0, blockComments, scriptTagAttrs, content ) {
blockComments = blockComments || '';
if ( importMapRE.test( scriptTagAttrs ) ) {
const imap = JSON.parse( content );
const imports = imap.imports;
if ( imports ) {
for ( const [ k, url ] of Object.entries( imports ) ) {
if ( url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) ) {
imports[ k ] = addPrefix( url );
}
}
}
content = JSON.stringify( imap, null, '\t' );
}
dataScripts.push( `${blockComments}<${kScript} ${scriptTagAttrs}>${content}</${kScript}>` );
return '';
} );
htmlParts.html.sources[ 0 ].source += dataScripts.join( '\n' );
htmlParts.html.sources[ 0 ].source += scripts.join( '\n' );
// add style section if there is non
if ( html.indexOf( '${css}' ) < 0 ) {
html = html.replace( '</head>', '<style>\n${css}</style>\n</head>' );
}
// add hackedparams section.
// We need a way to pass parameters to a blob. Normally they'd be passed as
// query params but that only works in Firefox >:(
html = html.replace( '</head>', '<script id="hackedparams">window.hackedParams = ${hackedParams}\n</script>\n</head>' );
html = extraHTMLParsing( html, htmlParts );
let links = '';
html = html.replace( cssLinkRE, function ( p0, p1 ) {
if ( isCSSLinkRE.test( p1 ) ) {
const m = hrefRE.exec( p1 );
if ( m ) {
links += `@import url("${m[ 1 ]}");\n`;
}
return '';
} else {
return p0;
}
} );
htmlParts.css.sources[ 0 ].source = links + htmlParts.css.sources[ 0 ].source;
g.html = html;
}
addCorrectPrefix(href: any): string
¶
Parameters:
href
any
Returns: string
Calls:
href.startsWith
removeDotDotSlash
(
${prefix}/${href}).replace
Codeny`
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
**Returns:** `void`
**Calls:**
- `URL.revokeObjectURL`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `JSON.stringify`
- `dirname`
- `extra.split`
- `getJavaScriptBlob`
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function addCorrectPrefix( href ) {
return ( href.startsWith( '/' ) )
? `${rootPrefix}${href}`
: removeDotDotSlash( ( `${prefix}/${href}` ).replace( /\/.\//g, '/' ) );
}
addPrefix(url: any): any
¶
Parameters:
url
any
Returns: any
Calls:
url.indexOf
url.startsWith
removeDotDotSlash
addCorrectPrefix
CodelParts: any): string`
**Parameters:**
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
- **`htmlParts`** `any`
**Returns:** `string`
**Calls:**
- `makeBlobURLsForSources`
- `dirname`
- `source.replace`
- `JSON.stringify`
- `source.search`
- `source.substring( 0, scriptNdx ).match`
- `URL.createObjectURL`
- `URL.revokeObjectURL`
**Internal Comments:**
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
function addPrefix( url ) {
return url.indexOf( '://' ) < 0 && ! url.startsWith( 'data:' ) && url[ 0 ] !== '?'
? removeDotDotSlash( addCorrectPrefix( url ) )
: url;
}
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
main(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
setupEditor
document.querySelector
toggleSourcePane
Codee
async function main() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
setupEditor();
if ( query.startPane ) {
const button = document.querySelector( '.button-' + query.startPane );
toggleSourcePane( button );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getJavaScriptBlob(source: any): string
¶
Parameters:
source
any
Returns: string
Calls:
URL.createObjectURL
Codee
function getJavaScriptBlob( source ) {
const blob = new Blob( [ source ], { type: 'application/javascript' } );
return URL.createObjectURL( blob );
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
makeBlobURLsForSources(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
makeBlobURLForSourcesImpl
CodeceBlob`
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function makeBlobURLsForSources( scriptInfo ) {
++ blobGeneration;
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
makeBlobURLForSourcesImpl( scriptInfo );
}
makeBlobURLForSourcesImpl(scriptInfo: any): void
¶
Parameters:
scriptInfo
any
Returns: void
Calls:
URL.revokeObjectURL
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
JSON.stringify
dirname
extra.split
getJavaScriptBlob
Codes>
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
### `basename(path: any): any`
**Parameters:**
- **`path`** `any`
**Returns:** `any`
**Calls:**
- `path.lastIndexOf`
- `path.substring`
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function makeBlobURLForSourcesImpl( scriptInfo ) {
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
if ( scriptInfo.blobUrl ) {
URL.revokeObjectURL( scriptInfo.blobUrl );
}
scriptInfo.deps.forEach( makeBlobURLForSourcesImpl );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( depScriptInfo.blobUrl );
} );
scriptInfo.numLinesBeforeScript = 0;
if ( scriptInfo.isWorker ) {
const extra = `self.lessonSettings = ${JSON.stringify( lessonSettings )};
import '${dirname( scriptInfo.fqURL )}/resources/webgl-debug-helper.js';
import '${dirname( scriptInfo.fqURL )}/resources/lessons-worker-helper.js';`;
scriptInfo.numLinesBeforeScript = extra.split( '\n' ).length;
text = `${extra}\n${text}`;
}
scriptInfo.blobUrl = getJavaScriptBlob( text );
scriptInfo.munged = text;
}
}
getSourceBlob(htmlParts: any): string
¶
Parameters:
htmlParts
any
Returns: string
Calls:
makeBlobURLsForSources
dirname
source.replace
JSON.stringify
source.search
source.substring( 0, scriptNdx ).match
URL.createObjectURL
URL.revokeObjectURL
Internal Comments:
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources (x2)
// We basically assume url is https://foo/base/example.html so there will be 4 slashes (x2)
// If the path is longer than then we need '../' to back up so prefix works below (x2)
// This seems hacky. We are combining html/css/js into one html blob but we already made (x2)
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs (x2)
// are regenerated. It also means error reporting will work (x2)
Code `info.editors.forEach`
- `editorInfo.editor.layout`
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
- `editorInfo.editor.layout`
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getSourceBlob( htmlParts ) {
g.rootScriptInfo.source = htmlParts.js;
makeBlobURLsForSources( g.rootScriptInfo );
const dname = dirname( g.url );
// HACK! for webgl-2d-vs... those examples are not in /webgl they're in /webgl/resources
// We basically assume url is https://foo/base/example.html so there will be 4 slashes
// If the path is longer than then we need '../' to back up so prefix works below
const prefix = dname; //`${dname}${dname.split('/').slice(4).map(() => '/..').join('')}`;
let source = g.html;
source = source.replace( '${hackedParams}', JSON.stringify( g.query ) );
source = source.replace( '${html}', htmlParts.html );
source = source.replace( '${css}', htmlParts.css );
source = source.replace( '${js}', g.rootScriptInfo.munged ); //htmlParts.js);
source = source.replace( '<head>', `<head>
<link rel="stylesheet" href="${prefix}/resources/lesson-helper.css" type="text/css">
<script match="false">self.lessonSettings = ${JSON.stringify( lessonSettings )}</script>` );
source = source.replace( '</head>', `<script src="${prefix}/resources/webgl-debug-helper.js"></script>
<script src="${prefix}/resources/lessons-helper.js"></script>
</head>` );
const scriptNdx = source.search( /<script(\s+type="module"\s*)?>/ );
g.rootScriptInfo.numLinesBeforeScript = ( source.substring( 0, scriptNdx ).match( /\n/g ) || [] ).length;
const blob = new Blob( [ source ], { type: 'text/html' } );
// This seems hacky. We are combining html/css/js into one html blob but we already made
// a blob for the JS so let's replace that blob. That means it will get auto-released when script blobs
// are regenerated. It also means error reporting will work
const blobUrl = URL.createObjectURL( blob );
URL.revokeObjectURL( g.rootScriptInfo.blobUrl );
g.rootScriptInfo.blobUrl = blobUrl;
return blobUrl;
}
getSourcesFromEditor(): void
¶
Returns: void
Calls:
Object.values
source.editor.getValue
Internal Comments:
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
Codes.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
- `getScriptsImpl`
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getSourcesFromEditor() {
for ( const partTypeInfo of Object.values( htmlParts ) ) {
for ( const source of partTypeInfo.sources ) {
source.source = source.editor.getValue();
// hack: shouldn't store this twice. Also see other comment,
// should consolidate so scriptInfo is used for css and html
if ( source.scriptInfo ) {
source.scriptInfo.source = source.source;
}
}
}
}
getSourceBlobFromEditor(): string
¶
Returns: string
Calls:
getSourcesFromEditor
getSourceBlob
CodecriptInfo: any): any[]`
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
**Parameters:**
- **`scriptInfo`** `any`
**Returns:** `any[]`
**Calls:**
- `scripts.push`
- `scriptInfo.deps.map( getScriptsImpl ).flat`
- `scriptInfo.deps.forEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getSourceBlobFromEditor() {
getSourcesFromEditor();
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
getSourceBlobFromOrig(): string
¶
Returns: string
Calls:
getSourceBlob
CodeEach`
- `text.split( depScriptInfo.fqURL ).join`
- `basename`
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getSourceBlobFromOrig() {
return getSourceBlob( {
html: htmlParts.html.sources[ 0 ].source,
css: htmlParts.css.sources[ 0 ].source,
js: htmlParts.js.sources[ 0 ].source,
} );
}
dirname(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
CodenScriptInfo.text.split( `'${workerName}'` ).join`
- `scripts.map( ( nameText ) =>
- `scripts.map( ( nameText ) =>
basename(path: any): any
¶
Parameters:
path
any
Returns: any
Calls:
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
basename(path: any): any
¶path
any
any
path.lastIndexOf
path.substring
Codee(html: any): Promise
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
- **`html`** `any`
**Returns:** `Promise
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function basename( path ) {
const ndx = path.lastIndexOf( '/' );
return path.substring( ndx + 1 );
}
resize(): void
¶
Returns: void
Calls:
forEachHTMLPart
info.editors.forEach
editorInfo.editor.layout
CodenCodepen(): Promise
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
**Returns:** `Promise
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function resize() {
forEachHTMLPart( function ( info ) {
info.editors.forEach( ( editorInfo ) => {
editorInfo.editor.layout();
} );
} );
}
getScripts(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
getScriptsImpl
CodenJSFiddle(): Promise
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
**Returns:** `Promise
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getScripts( scriptInfo ) {
++ blobGeneration;
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
return getScriptsImpl( scriptInfo );
}
getScriptsImpl(scriptInfo: any): any[]
¶
Parameters:
scriptInfo
any
Returns: any[]
Calls:
scripts.push
scriptInfo.deps.map( getScriptsImpl ).flat
scriptInfo.deps.forEach
text.split( depScriptInfo.fqURL ).join
basename
CodenJSGist(): Promise
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
**Returns:** `Promise
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
\n`;
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getScriptsImpl( scriptInfo ) {
const scripts = [];
if ( scriptInfo.blobGenerationId !== blobGeneration ) {
scriptInfo.blobGenerationId = blobGeneration;
scripts.push( ...scriptInfo.deps.map( getScriptsImpl ).flat() );
let text = scriptInfo.source;
scriptInfo.deps.forEach( ( depScriptInfo ) => {
text = text.split( depScriptInfo.fqURL ).join( `worker-${basename( depScriptInfo.fqURL )}` );
} );
scripts.push( {
name: `worker-${basename( scriptInfo.fqURL )}`,
text,
} );
}
return scripts;
}
makeScriptsForWorkers(scriptInfo: any): { js: any; html: string; }
¶
Parameters:
scriptInfo
any
Returns: { js: any; html: string; }
Calls:
getScripts
mainScriptInfo.text.split(
'${workerName}').join
- `scripts.map( ( nameText ) => {
const { name, text } = nameText; return `<script id="${name}" type="x-worker">\n${text}\nns:** `void`
Calls:
e.source.postMessage
} ).join`
Internal Comments:
Code*Calls:**
- `e.source.postMessage`
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
- `e.source.postMessage`
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function makeScriptsForWorkers( scriptInfo ) {
const scripts = getScripts( scriptInfo );
if ( scripts.length === 1 ) {
return {
js: scripts[ 0 ].text,
html: '',
};
}
// scripts[last] = main script
// scripts[last - 1] = worker
const mainScriptInfo = scripts[ scripts.length - 1 ];
const workerScriptInfo = scripts[ scripts.length - 2 ];
const workerName = workerScriptInfo.name;
mainScriptInfo.text = mainScriptInfo.text.split( `'${workerName}'` ).join( 'getWorkerBlob()' );
const html = scripts.map( ( nameText ) => {
const { name, text } = nameText;
return `<script id="${name}" type="x-worker">\n${text}\n</script>\n`;
} ).join( '\n' );
const init = `
// ------
// Creates Blobs for the Scripts so things can be self contained for snippets/JSFiddle/Codepen
// even though they are using workers
//
(function() {
const idsToUrls = [];
const scriptElements = [...document.querySelectorAll('script[type=x-worker]')];
for (const scriptElement of scriptElements) {
let text = scriptElement.text;
for (const {id, url} of idsToUrls) {
text = text.split(id).join(url);
}
const blob = new Blob([text], {type: 'application/javascript'});
const url = URL.createObjectURL(blob);
const id = scriptElement.id;
idsToUrls.push({id, url});
}
window.getWorkerBlob = function() {
return idsToUrls.pop().url;
};
import(window.getWorkerBlob());
}());
`;
return {
js: init,
html,
};
}
fixHTMLForCodeSite(html: any): Promise<any>
¶
Parameters:
html
any
Returns: Promise<any>
Calls:
html.replace
CodeCalls:**
- `s.split( '\n' ).map( s =>
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
- `s.split( '\n' ).map( s =>
openInCodepen(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function fixHTMLForCodeSite( html ) {
html = html.replace( lessonHelperScriptRE, '' );
html = html.replace( webglDebugHelperScriptRE, '' );
return html;
}
openInCodepen(): Promise<void>
¶Promise<void>
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
JSON.stringify
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.querySelector`
- `dialogElem.querySelector`
- `lessonEditorSettings.tags.filter( f =>
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `lessonEditorSettings.tags.filter( f =>
openInJSFiddle(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function openInCodepen() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const pen = {
title: g.title,
description: 'from: ' + g.url,
tags: lessonEditorSettings.tags,
editors: '101',
html: scripts.html + html,
css: htmlParts.css.sources[ 0 ].source,
js: comment + code,
};
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_blank" action="https://codepen.io/pen/define" class="hidden">'
<input type="hidden" name="data">
<input type="submit" />
"</form>"
`;
elem.querySelector( 'input[name=data]' ).value = JSON.stringify( pen );
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSFiddle(): Promise<void>
¶Promise<void>
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codet.startsWith`
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function openInJSFiddle() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form method="POST" target="_black" action="https://jsfiddle.net/api/mdn/" class="hidden">
<input type="hidden" name="html" />
<input type="hidden" name="css" />
<input type="hidden" name="js" />
<input type="hidden" name="title" />
<input type="hidden" name="wrap" value="b" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=html]' ).value = scripts.html + html;
elem.querySelector( 'input[name=css]' ).value = htmlParts.css.sources[ 0 ].source;
elem.querySelector( 'input[name=js]' ).value = comment + code;
elem.querySelector( 'input[name=title]' ).value = g.title;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openInJSGist(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
window.open
e.source.postMessage
window.addEventListener
CoderBase64.charAt`
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function openInJSGist() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const gist = {
name: g.title,
settings: {},
files: [
{ name: 'index.html', content: scripts.html + html, },
{ name: 'index.css', content: htmlParts.css.sources[ 0 ].source, },
{ name: 'index.js', content: comment + code, },
],
};
window.open( 'https://jsgist.org/?newGist=true', '_blank' );
const send = ( e ) => {
e.source.postMessage( { type: 'newGist', data: gist }, '*' );
};
window.addEventListener( 'message', send, { once: true } );
}
send(e: any): void
¶
Parameters:
e
any
Returns: void
Calls:
e.source.postMessage
Coderessed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
- `uncompressed.charAt`
- `Object.prototype.hasOwnProperty.call`
- `context_w.charCodeAt`
- `context_data.push`
- `getCharFromInt`
- `Math.pow`
- `String`
- `context_data.join`
**Internal Comments:**
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
indent4(s: any): any
¶
Parameters:
s
any
Returns: any
Calls:
s.split( '\n' ).map( s =>
${s}).join
Code>
### `compress(input: any): string`
**Parameters:**
- **`input`** `any`
**Returns:** `string`
**Calls:**
- `compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace`
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
openInStackOverflow(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
makeScriptsForWorkers
fixJSForCodeSite
fixHTMLForCodeSite
/\bimport\b/.test
indent4
document.querySelector
dialogElem.querySelector
lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join
Internal Comments:
Code`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
- **`parameters`** `any`
**Returns:** `string`
**Calls:**
- `compress`
- `JSON.stringify`
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function openInStackOverflow() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = makeScriptsForWorkers( g.rootScriptInfo );
const code = await fixJSForCodeSite( scripts.js );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const mainHTML = scripts.html + html;
const mainJS = comment + code;
const mainCSS = htmlParts.css.sources[ 0 ].source;
const asModule = /\bimport\b/.test( mainJS );
// Three.js wants us to use modules but Stack Overflow doesn't support them
const text = asModule
? `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<script type="module">
${indent4( mainJS )}
</script>
<!-- end snippet -->
`
: `
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
${indent4( mainJS )}
<!-- language: lang-css -->
${indent4( mainCSS )}
<!-- language: lang-html -->
${indent4( mainHTML )}
<!-- end snippet -->
`;
const dialogElem = document.querySelector( '.copy-dialog' );
dialogElem.style.display = '';
const copyAreaElem = dialogElem.querySelector( '.copy-area' );
copyAreaElem.textContent = text;
const linkElem = dialogElem.querySelector( 'a' );
const tags = lessonEditorSettings.tags.filter( f => ! f.endsWith( '.org' ) ).join( ' ' );
linkElem.href = `https://stackoverflow.com/questions/ask?&tags=javascript ${tags}`;
}
htmlTemplate(s: any): string
¶
Parameters:
s
any
Returns: string
Calls:
s.script.startsWith
Code(): Promise
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
**Calls:**
- `getSourcesFromEditor`
- `getScripts`
- `scripts.pop`
- `fixJSForCodeSite`
- `fixHTMLForCodeSite`
- `scripts.map`
- `scripts.reduce`
- `htmlTemplate`
- `JSON.stringify`
- `Object.values`
- `file.content.split( name ).join`
- `getParameters`
- `document.createElement`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function htmlTemplate( s ) {
return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>${s.title}</title>
<style>
${s.css}
</style>
</head>
<body>
${s.body}
</body>
${s.script.startsWith( '<' )
? s.script
: `
<script type="module">
${s.script}
</script>
`}
</html>`;
}
compressToBase64(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
_compress
keyStrBase64.charAt
Codeent`
- `elem.querySelector`
- `window.frameElement.ownerDocument.body.appendChild`
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
- `elem.querySelector( 'form' ).submit`
- `window.frameElement.ownerDocument.body.removeChild`
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function compressToBase64( input ) {
if ( input === null ) {
return '';
}
const res = _compress( input, 6, function ( a ) {
return keyStrBase64.charAt( a );
} );
switch ( res.length % 4 ) { // To produce valid Base64
default: // When could this happen ?
case 0 : return res;
case 1 : return res + '===';
case 2 : return res + '==';
case 3 : return res + '=';
}
}
_compress(uncompressed: any, bitsPerChar: any, getCharFromInt: any): string
¶
Parameters:
uncompressed
any
bitsPerChar
any
getCharFromInt
any
Returns: string
Calls:
uncompressed.charAt
Object.prototype.hasOwnProperty.call
context_w.charCodeAt
context_data.push
getCharFromInt
Math.pow
String
context_data.join
Internal Comments:
// Add wc to the dictionary. (x4)
// Output the code for w.
// Mark the end of the stream (x3)
// Flush the last char
Codeoid`
**Calls:**
- `fn`
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
**Calls:**
- `fn`
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function _compress( uncompressed, bitsPerChar, getCharFromInt ) {
let i;
let value;
const context_dictionary = {};
const context_dictionaryToCreate = {};
let context_c = '';
let context_wc = '';
let context_w = '';
let context_enlargeIn = 2; // Compensate for the first entry which should not count
let context_dictSize = 3;
let context_numBits = 2;
const context_data = [];
let context_data_val = 0;
let context_data_position = 0;
let ii;
for ( ii = 0; ii < uncompressed.length; ii += 1 ) {
context_c = uncompressed.charAt( ii );
if ( ! Object.prototype.hasOwnProperty.call( context_dictionary, context_c ) ) {
context_dictionary[ context_c ] = context_dictSize ++;
context_dictionaryToCreate[ context_c ] = true;
}
context_wc = context_w + context_c;
if ( Object.prototype.hasOwnProperty.call( context_dictionary, context_wc ) ) {
context_w = context_wc;
} else {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
// Add wc to the dictionary.
context_dictionary[ context_wc ] = context_dictSize ++;
context_w = String( context_c );
}
}
// Output the code for w.
if ( context_w !== '' ) {
if ( Object.prototype.hasOwnProperty.call( context_dictionaryToCreate, context_w ) ) {
if ( context_w.charCodeAt( 0 ) < 256 ) {
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 8; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
} else {
value = 1;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | value;
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = 0;
}
value = context_w.charCodeAt( 0 );
for ( i = 0; i < 16; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_enlargeIn = Math.pow( 2, context_numBits );
context_numBits ++;
}
delete context_dictionaryToCreate[ context_w ];
} else {
value = context_dictionary[ context_w ];
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
}
context_enlargeIn --;
if ( context_enlargeIn === 0 ) {
context_numBits ++;
}
}
// Mark the end of the stream
value = 2;
for ( i = 0; i < context_numBits; i ++ ) {
context_data_val = ( context_data_val << 1 ) | ( value & 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data_position = 0;
context_data.push( getCharFromInt( context_data_val ) );
context_data_val = 0;
} else {
context_data_position ++;
}
value = value >> 1;
}
// Flush the last char
for ( ;; ) {
context_data_val = ( context_data_val << 1 );
if ( context_data_position === bitsPerChar - 1 ) {
context_data.push( getCharFromInt( context_data_val ) );
break;
} else {
context_data_position ++;
}
}
return context_data.join( '' );
}
compress(input: any): string
¶
Parameters:
input
any
Returns: string
Calls:
compressToBase64( input ) .replace( /\+/g, '-' ) // Convert '+' to '-' .replace( /\//g, '_' ) // Convert '/' to '_' .replace
Code*Calls:**
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
- `info.editors.forEach`
- `editorInfo.editor.layout`
- `addRemoveClass`
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function compress( input ) {
return compressToBase64( input )
.replace( /\+/g, '-' ) // Convert '+' to '-'
.replace( /\//g, '_' ) // Convert '/' to '_'
.replace( /=+$/, '' ); // Remove ending '='
}
getParameters(parameters: any): string
¶
Parameters:
parameters
any
Returns: string
Calls:
compress
JSON.stringify
Codeeturns:** `void`
**Calls:**
- `selectFile`
**Calls:**
- `selectFile`
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
openInCodeSandbox(): Promise<void>
¶
Returns: Promise<void>
Calls:
getSourcesFromEditor
getScripts
scripts.pop
fixJSForCodeSite
fixHTMLForCodeSite
scripts.map
scripts.reduce
htmlTemplate
JSON.stringify
Object.values
file.content.split( name ).join
getParameters
document.createElement
elem.querySelector
window.frameElement.ownerDocument.body.appendChild
elem.querySelector( 'form' ).submit
window.frameElement.ownerDocument.body.removeChild
Codebutton.addEventListener`
- `toggleSourcePane`
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
- `runIfNeeded`
- `g.fullscreen.addEventListener`
- `g.run.addEventListener`
- `document.querySelector( '.button-codepen' ).addEventListener`
- `closeExport`
- `document.querySelector( '.button-jsfiddle' ).addEventListener`
- `document.querySelector( '.button-jsgist' ).addEventListener`
- `document.querySelector( '.button-stackoverflow' ).addEventListener`
- `document.querySelector( '.button-codesandbox' ).addEventListener`
- `g.resultButton.addEventListener`
- `toggleResultPane`
- `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
async function openInCodeSandbox() {
const comment = `// ${g.title}
// from ${g.url}
`;
getSourcesFromEditor();
const scripts = getScripts( g.rootScriptInfo );
const mainScript = scripts.pop();
const code = await fixJSForCodeSite( mainScript.text );
const html = await fixHTMLForCodeSite( htmlParts.html.sources[ 0 ].source );
const names = scripts.map( s => s.name );
const files = scripts.reduce( ( files, { name, text: content } ) => {
files[ name ] = { content };
return files;
}, {
'index.html': {
content: htmlTemplate( {
body: html,
css: htmlParts.css.sources[ 0 ].source,
title: g.title,
script: comment + code,
} ),
},
'sandbox.config.json': {
content: '{\n "template": "static"\n}\n',
},
'package.json': {
content: JSON.stringify( {
'name': 'static',
'version': '1.0.0',
'description': 'This is a static template with no bundling',
'main': 'index.html',
'scripts': {
'start': 'serve',
'build': 'echo This is a static template, there is no bundler or bundling involved!',
},
'license': 'MIT',
'devDependencies': {
'serve': '^11.2.0',
},
}, null, 2 ),
},
} );
for ( const file of Object.values( files ) ) {
for ( const name of names ) {
file.content = file.content.split( name ).join( `./${name}` );
}
}
const parameters = getParameters( { files } );
const elem = document.createElement( 'div' );
elem.innerHTML = `
<form action="https://codesandbox.io/api/v1/sandboxes/define" method="POST" target="_blank" class="hidden">
<input type="hidden" name="parameters" />
<input type="submit" />
</form>
`;
elem.querySelector( 'input[name=parameters]' ).value = parameters;
window.frameElement.ownerDocument.body.appendChild( elem );
elem.querySelector( 'form' ).submit();
window.frameElement.ownerDocument.body.removeChild( elem );
}
openExport(): void
¶
Returns: void
Calls:
exportDialogElem.firstElementChild.focus
Code `window.addEventListener`
- `showEditorSubPane`
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
- `showOtherIfAllPanesOff`
- `resize`
- `run`
**Internal Comments:**
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function openExport() {
exportDialogElem.style.display = '';
exportDialogElem.firstElementChild.focus();
}
closeExport(fn: any): () => void
¶
Parameters:
fn
any
Returns: () => void
Calls:
fn
Code*Calls:**
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
- `toggleIFrameFullscreen`
- `resize`
- `runIfNeeded`
- `console.error`
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
selectFile(info: any, ndx: any, fileDivs: any): void
¶
Parameters:
info
any
ndx
any
fileDivs
any
Returns: void
Calls:
info.editors.forEach
editorInfo.editor.layout
addRemoveClass
Codee
function selectFile( info, ndx, fileDivs ) {
if ( info.editors.length <= 1 ) {
return;
}
info.editors.forEach( ( editorInfo, i ) => {
const selected = i === ndx;
editorInfo.div.style.display = selected ? '' : 'none';
editorInfo.editor.layout();
addRemoveClass( fileDivs.children[ i ], 'fileSelected', selected );
} );
}
showEditorSubPane(type: any, ndx: any): void
¶
Parameters:
type
any
ndx
any
Returns: void
Calls:
selectFile
Code
setupEditor(): void
¶
Returns: void
Calls:
forEachHTMLPart
document.querySelector
info.pane.querySelector
info.sources.map
document.createElement
basename
info.files.appendChild
div.addEventListener
selectFile
info.code.appendChild
runEditor
info.button.addEventListener
toggleSourcePane
runIfNeeded
g.fullscreen.addEventListener
g.run.addEventListener
document.querySelector( '.button-codepen' ).addEventListener
closeExport
document.querySelector( '.button-jsfiddle' ).addEventListener
document.querySelector( '.button-jsgist' ).addEventListener
document.querySelector( '.button-stackoverflow' ).addEventListener
document.querySelector( '.button-codesandbox' ).addEventListener
g.resultButton.addEventListener
toggleResultPane
window.addEventListener
showEditorSubPane
showOtherIfAllPanesOff
resize
run
Internal Comments:
Code: any, className: any): boolean`
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
**Parameters:**
- **`elem`** `any`
- **`className`** `any`
**Returns:** `boolean`
**Calls:**
- `removeClass`
- `addClass`
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function setupEditor() {
forEachHTMLPart( function ( info, ndx, name ) {
info.pane = document.querySelector( '.panes>.' + name );
info.code = info.pane.querySelector( '.code' );
info.files = info.pane.querySelector( '.files' );
info.editors = info.sources.map( ( sourceInfo, ndx ) => {
if ( info.sources.length > 1 ) {
const div = document.createElement( 'div' );
div.textContent = basename( sourceInfo.name );
info.files.appendChild( div );
div.addEventListener( 'click', () => {
selectFile( info, ndx, info.files );
} );
}
const div = document.createElement( 'div' );
info.code.appendChild( div );
const editor = runEditor( div, sourceInfo.source, info.language );
sourceInfo.editor = editor;
return {
div,
editor,
};
} );
info.button = document.querySelector( '.button-' + name );
info.button.addEventListener( 'click', function () {
toggleSourcePane( info.button );
runIfNeeded();
} );
} );
g.fullscreen = document.querySelector( '.button-fullscreen' );
g.fullscreen.addEventListener( 'click', toggleFullscreen );
g.run = document.querySelector( '.button-run' );
g.run.addEventListener( 'click', run );
g.iframe = document.querySelector( '.result>iframe' );
g.other = document.querySelector( '.panes .other' );
document.querySelector( '.button-codepen' ).addEventListener( 'click', closeExport( openInCodepen ) );
document.querySelector( '.button-jsfiddle' ).addEventListener( 'click', closeExport( openInJSFiddle ) );
document.querySelector( '.button-jsgist' ).addEventListener( 'click', closeExport( openInJSGist ) );
document.querySelector( '.button-stackoverflow' ).addEventListener( 'click', closeExport( openInStackOverflow ) );
document.querySelector( '.button-codesandbox' ).addEventListener( 'click', closeExport( openInCodeSandbox ) );
//document.querySelector('.button-stackblitz').addEventListener('click', openInStackBlitz);
g.result = document.querySelector( '.panes .result' );
g.resultButton = document.querySelector( '.button-result' );
g.resultButton.addEventListener( 'click', function () {
toggleResultPane();
runIfNeeded();
} );
g.result.style.display = 'none';
toggleResultPane();
if ( window.innerWidth >= 1000 ) {
toggleSourcePane( htmlParts.js.button );
}
window.addEventListener( 'resize', resize );
showEditorSubPane( 'js', 0 );
showOtherIfAllPanesOff();
document.querySelector( '.other .loading' ).style.display = 'none';
resize();
run();
}
toggleFullscreen(): void
¶
Returns: void
Calls:
toggleIFrameFullscreen
resize
runIfNeeded
console.error
Codes>
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
### `toggleIFrameFullscreen(childWindow: any): void`
**Parameters:**
- **`childWindow`** `any`
**Returns:** `void`
**Calls:**
- `toggleClass`
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function toggleFullscreen() {
try {
toggleIFrameFullscreen( window );
resize();
runIfNeeded();
} catch ( e ) {
console.error(e); // eslint-disable-line
}
}
runIfNeeded(): void
¶
Returns: void
Calls:
run
Codeails>
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
run(): void
¶
Returns: void
Calls:
getSourceBlobFromEditor
g.iframe.contentWindow.location.replace
Internal Comments:
// g.iframe.src = url; (x7)
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286 (x7)
Codess`
- `removeClass`
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
- `addClass`
- `removeClass`
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function run() {
g.setPosition = false;
const url = getSourceBlobFromEditor();
// g.iframe.src = url;
// work around firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=1828286
g.iframe.contentWindow.location.replace( url );
}
addClass(elem: any, className: any): void
¶
Parameters:
elem
any
className
any
Returns: void
Calls:
elem.className.split
parts.indexOf
CodeHTMLPart`
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
- `addClass`
- `removeClass`
- `showOtherIfAllPanesOff`
- `resize`
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function addClass( elem, className ) {
const parts = elem.className.split( ' ' );
if ( parts.indexOf( className ) < 0 ) {
elem.className = elem.className + ' ' + className;
}
}
removeClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
elem.className.split
parts.indexOf
parts.splice
parts.join
Code(): void`
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
**Returns:** `void`
**Calls:**
- `showingResultPane`
- `addRemoveClass`
- `showOtherIfAllPanesOff`
- `resize`
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function removeClass( elem, className ) {
const parts = elem.className.split( ' ' );
const numParts = parts.length;
for ( ;; ) {
const ndx = parts.indexOf( className );
if ( ndx < 0 ) {
break;
}
parts.splice( ndx, 1 );
}
if ( parts.length !== numParts ) {
elem.className = parts.join( ' ' );
return true;
}
return false;
}
toggleClass(elem: any, className: any): boolean
¶
Parameters:
elem
any
className
any
Returns: boolean
Calls:
removeClass
addClass
Code*Calls:**
- `showingResultPane`
- `forEachHTMLPart`
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
- `showingResultPane`
- `forEachHTMLPart`
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function toggleClass( elem, className ) {
if ( removeClass( elem, className ) ) {
return false;
} else {
addClass( elem, className );
return true;
}
}
toggleIFrameFullscreen(childWindow: any): void
¶
Parameters:
childWindow
any
Returns: void
Calls:
toggleClass
Codeeturns:** `any`
**Calls:**
- `htmlParts[ type ].sources.findIndex`
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
**Calls:**
- `htmlParts[ type ].sources.findIndex`
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function toggleIFrameFullscreen( childWindow ) {
const frame = childWindow.frameElement;
if ( frame ) {
const isFullScreen = toggleClass( frame, 'fullscreen' );
frame.ownerDocument.body.style.overflow = isFullScreen ? 'hidden' : '';
}
}
addRemoveClass(elem: any, className: any, add: any): void
¶
Parameters:
elem
any
className
any
add
any
Returns: void
Calls:
addClass
removeClass
Coderl: any; actualLineNo: any; }`
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
**Calls:**
- `Object.values( g.scriptInfos ).find`
- `basename`
- `getEditorNdxByBlobUrl`
- `showEditorSubPane`
- `editor.setPosition`
- `editor.revealLineInCenterIfOutsideViewport`
- `editor.focus`
**Internal Comments:**
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function addRemoveClass( elem, className, add ) {
if ( add ) {
addClass( elem, className );
} else {
removeClass( elem, className );
}
}
toggleSourcePane(pressedButton: any): void
¶
Parameters:
pressedButton
any
Returns: void
Calls:
forEachHTMLPart
addClass
removeClass
showOtherIfAllPanesOff
resize
Code any, source: any, language: any): any`
**Parameters:**
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
- **`parent`** `any`
- **`source`** `any`
- **`language`** `any`
**Returns:** `any`
**Calls:**
- `monaco.editor.create`
**Internal Comments:**
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function toggleSourcePane( pressedButton ) {
forEachHTMLPart( function ( info ) {
const pressed = pressedButton === info.button;
if ( pressed && ! info.showing ) {
addClass( info.button, 'show' );
info.pane.style.display = 'flex';
info.showing = true;
} else {
removeClass( info.button, 'show' );
info.pane.style.display = 'none';
info.showing = false;
}
} );
showOtherIfAllPanesOff();
resize();
}
showingResultPane(): boolean
¶
Returns: boolean
Code.editor.create`
**Internal Comments:**
- `monaco.editor.create`
**Internal Comments:**
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
toggleResultPane(): void
¶
Returns: void
Calls:
showingResultPane
addRemoveClass
showOtherIfAllPanesOff
resize
Codery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
- `getQuery`
- `getFQUrl`
- `getSearch`
- `getHTML`
- `console.log`
- `parseHTML`
- `getSourceBlobFromOrig`
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function toggleResultPane() {
const showing = showingResultPane();
g.result.style.display = showing ? 'none' : 'block';
addRemoveClass( g.resultButton, 'show', ! showing );
showOtherIfAllPanesOff();
resize();
}
showOtherIfAllPanesOff(): void
¶
Returns: void
Calls:
showingResultPane
forEachHTMLPart
CodeSubstitutions(): void`
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
**Returns:** `void`
**Calls:**
- `[ ...document.querySelectorAll( '[data-subst]' ) ].forEach`
- `document.querySelectorAll`
- `elem.dataset.subst.split( '&' ).forEach`
- `pair.split`
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function showOtherIfAllPanesOff() {
let paneOn = showingResultPane();
forEachHTMLPart( function ( info ) {
paneOn = paneOn || info.showing;
} );
g.other.style.display = paneOn ? 'none' : 'block';
}
getEditorNdxByBlobUrl(type: any, url: any): any
¶
Parameters:
type
any
url
any
Returns: any
Calls:
htmlParts[ type ].sources.findIndex
Code*Returns:** `void`
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
**Calls:**
- `getQuery`
- `window.navigator.userAgent.match`
- `runAsBlob`
- `applySubstitutions`
- `require.config`
- `require`
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}
function getEditorNdxByBlobUrl( type, url ) {
return htmlParts[ type ].sources.findIndex( source => source.scriptInfo.blobUrl === url );
}
getActualLineNumberAndMoveTo(url: any, lineNo: any, colNo: any): { origUrl: any; actualLineNo: any; }
¶
Parameters:
url
any
lineNo
any
colNo
any
Returns: { origUrl: any; actualLineNo: any; }
Calls:
Object.values( g.scriptInfos ).find
basename
getEditorNdxByBlobUrl
showEditorSubPane
editor.setPosition
editor.revealLineInCenterIfOutsideViewport
editor.focus
Internal Comments:
Code
function getActualLineNumberAndMoveTo( url, lineNo, colNo ) {
let origUrl = url;
let actualLineNo = lineNo;
const scriptInfo = Object.values( g.scriptInfos ).find( scriptInfo => scriptInfo.blobUrl === url );
if ( scriptInfo ) {
actualLineNo = lineNo - scriptInfo.numLinesBeforeScript;
origUrl = basename( scriptInfo.fqURL );
if ( ! g.setPosition ) {
// Only set the first position
g.setPosition = true;
const editorNdx = getEditorNdxByBlobUrl( 'js', url );
if ( editorNdx >= 0 ) {
showEditorSubPane( 'js', editorNdx );
const editor = htmlParts.js.editors[ editorNdx ].editor;
editor.setPosition( {
lineNumber: actualLineNo,
column: colNo,
} );
editor.revealLineInCenterIfOutsideViewport( actualLineNo );
editor.focus();
}
}
}
return { origUrl, actualLineNo };
}
runEditor(parent: any, source: any, language: any): any
¶
Parameters:
parent
any
source
any
language
any
Returns: any
Calls:
monaco.editor.create
Internal Comments:
Code
runAsBlob(): Promise<void>
¶
Returns: Promise<void>
Calls:
getQuery
getFQUrl
getSearch
getHTML
console.log
parseHTML
getSourceBlobFromOrig
Code
async function runAsBlob() {
const query = getQuery();
g.url = getFQUrl( query.url );
g.query = getSearch( g.url );
let html;
try {
html = await getHTML( query.url );
} catch ( err ) {
console.log(err); // eslint-disable-line
return;
}
await parseHTML( query.url, html );
window.location.href = getSourceBlobFromOrig();
}
applySubstitutions(): void
¶
Returns: void
Calls:
[ ...document.querySelectorAll( '[data-subst]' ) ].forEach
document.querySelectorAll
elem.dataset.subst.split( '&' ).forEach
pair.split
Code
start(): void
¶
Returns: void
Calls:
getQuery
window.navigator.userAgent.match
runAsBlob
applySubstitutions
require.config
require
Code
function start() {
const parentQuery = getQuery( window.parent.location.search );
const isSmallish = window.navigator.userAgent.match( /Android|iPhone|iPod|Windows Phone/i );
const isEdge = window.navigator.userAgent.match( /Edge/i );
if ( isEdge || isSmallish || parentQuery.editor === 'false' ) {
runAsBlob();
// var url = query.url;
// window.location.href = url;
} else {
applySubstitutions();
require.config( { paths: { 'vs': 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } } );
require( [ 'vs/editor/editor.main' ], main );
}
}