//- Mixins and associated functions //- _docsFor: used to identify the language this version of the docs if for; //- Should be one of: 'ts', 'dart' or 'js'. Set in lang specific _util-fns file. - var _docsFor = ''; //- Should match `_docsFor`, but in this case provides the full capitalized //- name of the language. - var _Lang = 'TypeScript'; //- Simple "macros" used via interpolation in text: //- e.g., the #{_priv}el variable has an `@Input` #{_decorator}. //- Use #{_decorator} whereever the word "decorator" is expected, provided it is not //- preceded by the article "a". (E.g., will be "annotation" for Dart) - var _decorator = 'decorator'; //- Articles (which toggle between 'a' and 'an'). Used for, e.g., //- array vs. list; decorator vs. annotation. - var _a = 'a'; - var _an = 'an'; //- TS arrays vs. Dart lists - var _Array = 'Array'; - var _array = 'array'; //- Promise vs. Future, etc - var _Promise = 'Promise'; - var _PromiseUrl = 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise'; - var _PromiseLinked = '' + _Promise + ''; - var _Observable = 'Observable'; //- Directories & folders - var _appDir = 'app'; - var _indexHtmlDir = 'project root'; - var _mainDir = _appDir; //- Location of sample code - var _liveLink = 'live link'; //- NgModule related - var _AppModuleVsAppComp = 'AppModule' - var _appModuleTsVsAppCompTs = 'app/app.module.ts' - var _appModuleTsVsMainTs = 'app/app.module.ts' - var _bootstrapModule = 'bootstrapModule' - var _moduleVsComp = 'module' - var _moduleVsRootComp = 'module' - var _platformBrowserDynamicVsBootStrap = 'platformBrowserDynamic' //- Other - var _truthy = 'truthy'; - var _falsey = 'falsey'; //- Used to prefix identifiers that are private. In Dart this will be '_'. - var _priv = ''; //- Use to conditionally include the block that follows +ifDocsFor(...). //- Generally favor use of Jade named blocks instead. ifDocsFor is convenient //- for prose that should appear only in one language version. mixin ifDocsFor(langPattern) if _docsFor.toLowerCase().match(langPattern.toLowerCase()) block //- Use to map inlined (prose) TS paths into, say, Dart paths via the //- adjustTsExamplePathForDart transformer function. mixin adjExPath(path) if adjustTsExamplePathForDart | #{adjustTsExamplePathForDart(path)} else | #{path} mixin includeShared(filePath, region) - var newPath = translatePath(filePath, region); !=partial(newPath) mixin makeExample(_filePath, region, _title, stylePatterns) - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); - var filePath = adjustments.filePath; - var title = adjustments.title; - var language = attributes.language || getExtn(filePath); - var frag = getFrag(filePath, region); - var defaultFormat = frag.split('\n').length > 2 ? "linenums" : ""; - var format = attributes.format || defaultFormat; - if (attributes.format === '.') format = ''; - var avoid = !!attributes.avoid; if (title) if (avoid) .example-title.avoid AVOID: #{title} else .example-title #{title} code-example(language="#{language}" format="#{format}") != styleString(frag, stylePatterns) //- Like makeExample, but: (1) doesn't show line numbers. (2) If region //- is omitted and title is 'foo (r)' then region is taken as 'r'. //- (3) Title will always end with a phrase in parentheses; if no such //- ending is given or is just (), then the title will be suffixed with //- either "(excerpt)", or "(#{_region})" when _region is defined. mixin makeExcerpt(_filePath, _region, _title, stylePatterns) - var matches = _filePath.match(/(.*)\s+\(([^\)]*)\)$/); - var parenText; - if (matches) { _filePath = matches[1]; parenText = matches[2]; } - var adjustments = adjustExamplePathAndTitle({filePath:_filePath, title:_title}); - var filePath = adjustments.filePath; - var title = adjustments.title; - var region = _region || (_region === '' ? '' : parenText); - var excerpt = parenText || region || 'excerpt'; - if (title) title = title + ' (' + excerpt + ')'; +makeExample(filePath, region, title, stylePatterns)(format='.') //- Get the doc example name either from `_example` if set, or //- extract the example name from `current`. - var getExampleName = function() { - var dir = current.path[current.path.length - 1]; - return _example ? _example : dir == 'latest' ? current.source : dir; - }; mixin makeTabs(filePaths, regions, tabNames, stylePatterns) - filePaths = strSplit(filePaths); - if (adjustTsExamplePathForDart) filePaths = filePaths.map(adjustTsExamplePathForDart); - regions = strSplit(regions, filePaths.length); - tabNames = strSplit(tabNames, filePaths.length); - if (adjustTsExampleTitleForDart) tabNames = tabNames.map(adjustTsExampleTitleForDart); code-tabs each filePath,index in filePaths - var region = regions[index].trim(); - var tabName = tabNames[index].trim(); - var language = attributes.language || getExtn(filePath); - var format = attributes.format || "linenums"; - var frag = getFrag(filePath, region); - var sps = Array.isArray(stylePatterns) ? stylePatterns[index] : stylePatterns; code-pane(language="#{language}" name="#{tabName}" format="#{format}") != styleString(frag, sps) mixin makeJson( filePath, jsonConfig, title, stylePatterns) - var language = attributes.language || getExtn(filePath); - var format = attributes.format || "linenums"; - var frag = getFrag(filePath, ''); - var json = unescapeHtml(frag); - var jsonExtract = extractJson(json, jsonConfig); - var avoid = !!attributes.avoid; if (title) if (avoid) .example-title.avoid #{title} else .example-title #{title} code-example(language="#{language}" format="#{format}") if (jsonExtract == 'ERROR') err ERROR: Unable to extract json using config: "#{jsonConfig.toString()}" else != styleString(jsonExtract, stylePatterns) - // Open (and close) an explanation
. See QuickStart script. function why(id, backTo) { var id = "#"+id; var el = document.querySelector(id); el.hidden=el.hidden=!el.hidden; if (el.hidden && backTo){ // the next line is required to work around a bug in WebKit (Chrome / Safari) location.href = "#"; location.href = "#" + backTo; } } script. function verbose(isVerbose) { isVerbose = !! isVerbose; var el = document.querySelector('button.verbose.off'); el.style.display = isVerbose ? 'block' : 'none'; var el = document.querySelector('button.verbose.on'); el.style.display = isVerbose ? 'none' : 'block'; CCSStylesheetRuleStyle('main','.l-verbose-section', 'display', isVerbose ? 'block' : 'none'); } script. function CCSStylesheetRuleStyle(stylesheet, selectorText, style, value){ /* returns the value of the element style of the rule in the stylesheet * If no value is given, reads the value * If value is given, the value is changed and returned * If '' (empty string) is given, erases the value. * The browser will apply the default one * * string stylesheet: part of the .css name to be recognized, e.g. 'default' * string selectorText: css selector, e.g. '#myId', '.myClass', 'thead td' * string style: camelCase element style, e.g. 'fontSize' * string value optional : the new value */ var CCSstyle = undefined, rules, sheet; for(var m in document.styleSheets){ sheet = document.styleSheets[m]; if(sheet.href && sheet.href.indexOf(stylesheet) != -1){ rules = sheet[document.all ? 'rules' : 'cssRules']; for(var n in rules){ console.log(rules[n].selectorText); if(rules[n].selectorText == selectorText){ CCSstyle = rules[n].style; break; } } break; } } if(value == undefined) return CCSstyle[style] else return CCSstyle[style] = value } //--------------------------------------------------------------------------------------------------------- //- Converts the given project-relative path (like 'app/main.ts') //- to a doc folder relative path (like 'quickstart/ts/app/main.ts') //- by prefixing it with '/ts/'. If title is not given, //- then the project-relative path is used, adjusted to remove numeric //- file version qualifiers; e.g. 'styles.1.css' becomes 'styles.css'. - var adjExampleProjPathAndTitle = function(ex/*:{filePath,title}*/) { - // E.g. of a project relative path is 'app/main.ts' - if (ex.title === null || ex.title === undefined) { - // Title is not given so take it to be ex.filePath. - // Title like styles.1.css or foo_1.dart? Then drop the '.1' or '_1' qualifier: - var matches = ex.filePath.match(/^(.*)[\._]\d(\.\w+)$/); - ex.title = matches ? matches[1] + matches[2] : ex.filePath; - } - ex.filePath = getExampleName() + '/' + _docsFor + '/' + ex.filePath; - return ex; - }; //- If the given path is project relative, then first convert it using //- adjExampleProjPathAndTitle(ex). Then the path is adjusted to match //- the documentation language. - var adjustExamplePathAndTitle = function(ex/*:{filePath,title}*/) { - // Not a doc folder relative path? Assume that it is app project relative. - if(isProjRelDir(ex.filePath)) adjExampleProjPathAndTitle(ex); - // Adjust doc folder relative paths if adjustment functions exist. - if(adjustTsExamplePathForDart) ex.filePath = adjustTsExamplePathForDart(ex.filePath); - if(adjustTsExampleTitleForDart) ex.title = adjustTsExampleTitleForDart(ex.title); - return ex; - }; //- Returns truthy iff path is example project relative. - var isProjRelDir = function(path) { - return !path.match(/\/(js|ts|dart)(-snippets)?\//) && !path.endsWith('e2e-spec.ts'); - // Last conjunct handles case for shared project e2e test file like - // cb-component-communication/e2e-spec.js (is shared between ts & dart) - // TODO: generalize: compare start with getExampleName(); which needs to be fixed. - }; - var translatePath = function(filePath, region) { - filePath = filePath.trim(); - var regionPad = (region && region.length) ? '-' + region.toString() : ''; - var matches = /{(.*)}.*/.exec(filePath); - if (matches) { - var topLevelDir = matches[1]; - var currentPath = current.path; - var subPaths = currentPath.slice(2); - // subPaths[subPaths.length - 1] = "_." + subPaths[subPaths.length - 1]; - subPaths[subPaths.length - 1] = "_fragments/" + subPaths[subPaths.length - 1]; - var newPath = getPathToDocs() + topLevelDir + '/' + subPaths.join("/"); - var result = newPath + regionPad + ".jade"; - } else { - var extn = getExtn(filePath); - var baseFileName = getBaseFileName(filePath); - var noExtnFileName = baseFileName.substr(0,baseFileName.length - (extn.length + 1)); - var folder = getFolder(filePath); - // var result = folder + "/_." + noExtnFileName + regionPad + "." + extn; - var result = folder + "/_fragments/" + noExtnFileName + regionPad + "." + extn; - } - return result - } - var EMPTY_STRINGS = [ '','','','','','','']; - var strSplit = function(str, length) { - var res; - str = str || ''; - if (!length) { - res = str.split(","); - } else { - res = str.split(","); - if (res.length < length) { - res = res.concat(EMPTY_STRINGS.slice(0, length - res.length)); - } - } - return res; - } - var getFrag = function(filePath, region) { - var fullFileName = getFragFilePath(filePath, region); - var frag = partial(fullFileName); - if (frag == null) { - return "BAD FILENAME: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs(); - } else { - // ``` gets translated to
.....
and we need - // to remove this from the fragment prefix is 11 long and suffix is 13 long - frag = frag.substring(11, frag.length-13); - // Uncomment next line for debugging. - // frag = "FileName: " + fullFileName + " Current path: " + current.path + " PathToDocs: " + getPathToDocs() + "\n" + frag; - return frag; - } - } - var extractJson = function(json, jsonConfig ) { - try { - if (jsonConfig) { - return extractJsonFragment(json, jsonConfig.rootPath || null, jsonConfig.paths || [], jsonConfig.space || " "); - } else { - return json; - } - } catch (e) { - return "ERROR"; - // return json; - } - } - var unescapeHtml = function(s) { - // can't break across multiple lines because of jade limitations. - return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'"); - } - var styleString = function(source, stylePatterns) { - if (stylePatterns) { - for (var styleName in stylePatterns) { - var rxs = stylePatterns[styleName]; - rxs = Array.isArray(rxs) ? rxs : [rxs]; - rxs.forEach(function(rx) { - source = applyStyle(source, styleName, rx ); - }); - } - } - return source; - } - var getFragFilePath = function (filePath, region) { - filePath = filePath.trim(); - var extn = getExtn(filePath); - var fileBase = filePath.substr(0,filePath.length - (extn.length + 1)); - var regionPad = (region && region.length) ? '-' + region.toString() : ''; - var fullFileName = getPathToFrags() + fileBase + regionPad + "." + extn + '.md'; - return fullFileName; - } //- styles a string according to a regular expression. //- The match groups resulting from the regexp application are what is styled //- (not the whole regexp). - var applyStyle = function(str, styleName, rx) { - var repls = {}; - var matches; - do { - matches = rx.exec(str); - if (matches) { - matches.slice(1).forEach(function(match) { - var repl = '' + match + ''; - repls[match] = { repl: repl, isGlobal: rx.global }; - }); - } - } while (matches != null && rx.global ); - for (var match in repls) { - var repl = repls[match]; - // var escapedMatch = match.replace(/\\/g,'\\').replace(/\(/g,'\(').replace(/\)/g, '\)').replace(/\./,'\.'); - // var rx2 = new RegExp(escapedMatch, repl.isGlobal ? "g" : ""); - var rx2 = match; - str = str.replace(rx2, repl.repl); - }; - return str; - } - var getExtn = function(fileName) { - var ix = fileName.lastIndexOf('.'); - return ix > 0 ? fileName.substr(ix+1) : ""; - } - var getBaseFileName = function(fileName) { - var ix = fileName.lastIndexOf('/'); - return ix > 0 ? fileName.substr(ix+1) : ""; - } - var getFolder = function(fileName) { - var ix = fileName.lastIndexOf('/'); - return ix > 0 ? fileName.substr(0, ix) : ""; - } - var getPathToDocs = function() { - // simple way to only take as many '../' sections as we need to back up to the 'docs' dir - // from the current document - // we will almost certainly never go 10 or 11 deep but ... - return current.pathToDocs || "../../../../../../../../../../../".substr(0, (current.path.length-2)*3); - } - var getPathToFrags = function() { - return getPathToDocs() + "_fragments/"; - } - var getPathToExamples = function() { - return getPathToDocs() + "_examples/"; - } //- Extract a subset of a json file in a specified order defined //- by extractPaths while retaining original order for any //- unspecified subobjects. //- //- based on the principle that JSON.parse(source) constructs objects //- in order from the top down in 'source' and JSON.stringify(source) iterates 'source' //- properties according to the order in which they were inserted. ( the spec actually //- discourages this assumption but this method will only //- run on node (v8) and the assumption seems safe there. ) - function extractJsonFragment(source, rootPath, extractPaths, space) { - var objSource = JSON.parse(source); - if (rootPath && rootPath.length > 0) { - objSource = getSubObject(objSource, rootPath); - } - var objDest = {}; - extractPaths.trim().split(",").forEach(function(dotPath) { - processPath(objSource, objDest, dotPath ); - }); - var result = JSON.stringify(objDest, null, space || " "); - return result; - function getSubObject(source, path) { - var nextSource = source; - var pathParts = path.trim().split("."); - while (pathParts.length > 0) { - var nextProp = pathParts.shift(); - nextSource = nextSource[nextProp]; - } - return nextSource; - } - function processPath(source, dest, dotPath) { - var nextSource = source; - var nextDest = dest; - var pathParts = dotPath.trim().split("."); - while (pathParts.length > 0) { - var nextProp = pathParts.shift(); - nextSource = nextSource[nextProp]; - if (pathParts.length > 0) { - var val = nextDest[nextProp] || {}; - nextDest[nextProp] = val; - nextDest = val; - } else { - nextDest[nextProp] = nextSource; - } - } - } - }