From 5b8df3494a20e43895e33a3171c432506e6df63a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jes=C3=BAs=20Rodr=C3=ADguez?= Date: Thu, 25 Aug 2016 19:44:22 +0200 Subject: [PATCH] chore: add embedded plunkers functionality (#2194) --- .gitignore | 2 + gulpfile.js | 6 +- public/_includes/_scripts-include.jade | 2 +- public/docs/ts/latest/guide/ngmodule.jade | 6 +- public/resources/css/main.scss | 1 + .../css/module/_embedded-plunker.scss | 3 + .../resources/images/plunker/placeholder.png | Bin 0 -> 20933 bytes .../resources/js/directives/live-example.js | 56 ++- tools/plunker-builder/builder.js | 320 ++++++++++++++++++ tools/plunker-builder/embeddedPlunker.js | 34 ++ tools/plunker-builder/plunkerBuilder.js | 309 ----------------- tools/plunker-builder/regularPlunker.js | 23 ++ 12 files changed, 431 insertions(+), 331 deletions(-) create mode 100644 public/resources/css/module/_embedded-plunker.scss create mode 100644 public/resources/images/plunker/placeholder.png create mode 100644 tools/plunker-builder/builder.js create mode 100644 tools/plunker-builder/embeddedPlunker.js delete mode 100644 tools/plunker-builder/plunkerBuilder.js create mode 100644 tools/plunker-builder/regularPlunker.js diff --git a/.gitignore b/.gitignore index b6d52bd9b9..91d27e6acf 100644 --- a/.gitignore +++ b/.gitignore @@ -25,6 +25,8 @@ www npm-debug*.log* *.plnkr.html plnkr.html +*.eplnkr.html +eplnkr.html *plnkr.no-link.html public/docs/*/latest/guide/cheatsheet.json protractor-results.txt diff --git a/gulpfile.js b/gulpfile.js index 8ca960a8dd..747931fa7a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -45,7 +45,8 @@ var STYLES_SOURCE_PATH = path.join(TOOLS_PATH, 'styles-builder/less'); var docShredder = require(path.resolve(TOOLS_PATH, 'doc-shredder/doc-shredder')); var exampleZipper = require(path.resolve(TOOLS_PATH, '_example-zipper/exampleZipper')); -var plunkerBuilder = require(path.resolve(TOOLS_PATH, 'plunker-builder/plunkerBuilder')); +var regularPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/regularPlunker')); +var embeddedPlunker = require(path.resolve(TOOLS_PATH, 'plunker-builder/embeddedPlunker')); var fsUtils = require(path.resolve(TOOLS_PATH, 'fs-utils/fsUtils')); const isSilent = !!argv.silent; @@ -603,7 +604,8 @@ gulp.task('build-dart-api-docs', ['_shred-api-examples', 'dartdoc'], function() }); gulp.task('build-plunkers', ['_copy-example-boilerplate'], function() { - return plunkerBuilder.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build }); + regularPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build }); + return embeddedPlunker.buildPlunkers(EXAMPLES_PATH, LIVE_EXAMPLES_PATH, { errFn: gutil.log, build: argv.build }); }); gulp.task('build-dart-cheatsheet', [], function() { diff --git a/public/_includes/_scripts-include.jade b/public/_includes/_scripts-include.jade index 9b4cd8048b..b9b2266f3e 100644 --- a/public/_includes/_scripts-include.jade +++ b/public/_includes/_scripts-include.jade @@ -64,4 +64,4 @@ script(src="//www.gstatic.com/feedback/api.js" type="text/javascript") script. - (function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}})(document,"script","twitter-wjs"); \ No newline at end of file + (function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}})(document,"script","twitter-wjs"); diff --git a/public/docs/ts/latest/guide/ngmodule.jade b/public/docs/ts/latest/guide/ngmodule.jade index 697cbe9c1a..fc8a0caaad 100644 --- a/public/docs/ts/latest/guide/ngmodule.jade +++ b/public/docs/ts/latest/guide/ngmodule.jade @@ -131,7 +131,7 @@ a#bootstrap :marked The samples in this chapter demonstrate the dynamic bootstrapping approach. - Try the live example. + Try the live example. ### Static bootstrapping with the Ahead-Of-Time (AOT) compiler @@ -606,7 +606,7 @@ a#feature-modules * No `ContactService` provider * No `HighlightDirective` conflict - Try the live example of version 2. + Try the live example. a#lazy-load .l-main-section @@ -782,7 +782,7 @@ a#hero-module The `CrisisModule` is much the same. There's nothing more to say that's new. - Try the live example. + Try the live example. a#shared-module .l-main-section diff --git a/public/resources/css/main.scss b/public/resources/css/main.scss index 0a0e019eab..f066ab6f72 100644 --- a/public/resources/css/main.scss +++ b/public/resources/css/main.scss @@ -55,6 +55,7 @@ @import 'module/features'; @import 'module/docs-landing'; @import 'module/copy'; +@import 'module/embedded-plunker'; /* * PRINT STYLES diff --git a/public/resources/css/module/_embedded-plunker.scss b/public/resources/css/module/_embedded-plunker.scss new file mode 100644 index 0000000000..0648c723be --- /dev/null +++ b/public/resources/css/module/_embedded-plunker.scss @@ -0,0 +1,3 @@ +live-example iframe { + height: 500px; +} diff --git a/public/resources/images/plunker/placeholder.png b/public/resources/images/plunker/placeholder.png new file mode 100644 index 0000000000000000000000000000000000000000..becea3bab39e0f9f8afd6aea43be80ec09a9e6ff GIT binary patch literal 20933 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 SQHKvu_v931^KLzQ`ab|modTKw literal 0 HcmV?d00001 diff --git a/public/resources/js/directives/live-example.js b/public/resources/js/directives/live-example.js index 1946d02f43..dc300f69a1 100644 --- a/public/resources/js/directives/live-example.js +++ b/public/resources/js/directives/live-example.js @@ -5,7 +5,7 @@ * app this directive is contained in. * * Usage: -* text +* text * Example: *

Run Try the live example

. * // ~/resources/live-examples/{chapter}/ts/plnkr.html @@ -15,6 +15,12 @@ * *

Run

. * // ~/resources/live-examples/{chapter}/ts/minimal.plnkr.html +* +* +* // ~/resources/live-examples/{chapter}/ts/eplnkr.html +* +* +* // ~/resources/live-examples/{chapter}/ts/minimal.eplnkr.html */ angularIO.directive('liveExample', ['$location', function ($location) { @@ -26,42 +32,60 @@ angularIO.directive('liveExample', ['$location', function ($location) { function span(text) { return '' + text + ''; } + function embeddedTemplate(src, name) { + return '
' + + '' + + '
' + + 'plunker'; + } + return { restrict: 'E', - + scope: true, compile: function (tElement, attrs) { var text = tElement.text() || 'live example'; var ex = attrs.name || NgIoUtil.getExampleName($location); - var plnkr = ''; + var embedded = attrs.hasOwnProperty('embedded'); + var plnkr = embedded ? 'eplnkr' : 'plnkr'; var href, template; if (attrs.plnkr) { - plnkr = attrs.plnkr + '.'; + plnkr = attrs.plnkr + '.' + plnkr; } var isForDart = attrs.lang === 'dart' || NgIoUtil.isDoc($location, 'dart'); var isForJs = attrs.lang === 'js' || NgIoUtil.isDoc($location, 'js'); var exLang = isForDart ? 'dart' : isForJs ? 'js' : 'ts'; - var href = isForDart - ? 'http://angular-examples.github.io/' + ex - : '/resources/live-examples/' + ex + '/' + exLang + '/' + plnkr + 'plnkr.html'; - // Link to live example. - var template = a(text, { href: href, target: '_blank' }); + if (attrs.hasOwnProperty('embedded') && !isForDart) { + href = '/resources/live-examples/' + ex + '/' + exLang + '/' + plnkr + '.html' + template = embeddedTemplate(href, plnkr); + } else { + var href = isForDart + ? 'http://angular-examples.github.io/' + ex + : '/resources/live-examples/' + ex + '/' + exLang + '/' + plnkr + '.html' - // The hosted example and sources are in different locations for Dart. - // Also show link to sources for Dart, unless noSource is specified. - if (isForDart && !attrs.hasOwnProperty('nosource')) { - var srcText = attrs.srcText || 'view source'; - var srcHref = 'http://github.com/angular-examples/' + ex; - template = span(template + ' (' + a(srcText, { href: srcHref, target: '_blank' }) + ')'); + // Link to live example. + var template = a(text, { href: href, target: '_blank' }); + + // The hosted example and sources are in different locations for Dart. + // Also show link to sources for Dart, unless noSource is specified. + if (isForDart && !attrs.hasOwnProperty('nosource')) { + var srcText = attrs.srcText || 'view source'; + var srcHref = 'http://github.com/angular-examples/' + ex; + template = span(template + ' (' + a(srcText, { href: srcHref, target: '_blank' }) + ')'); + } } // UPDATE ELEMENT WITH NEW TEMPLATE tElement.html(template); // RETURN ELEMENT - return function (scope, element, attrs) { }; + return function (scope, element, attrs) { + scope.toggleEmbedded = function() { + scope.embeddedShow = !scope.embeddedShow; + } + }; } }; }]); diff --git a/tools/plunker-builder/builder.js b/tools/plunker-builder/builder.js new file mode 100644 index 0000000000..d8f910767d --- /dev/null +++ b/tools/plunker-builder/builder.js @@ -0,0 +1,320 @@ +'use strict'; + +// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes +var path = require('canonical-path'); +var Q = require('q'); +var _ = require('lodash'); +var jsdom = require("jsdom"); +var fs = require("fs"); +var globby = require('globby'); +var mkdirp = require('mkdirp'); + +var indexHtmlTranslator = require('./indexHtmlTranslator'); +var regionExtractor = require('../doc-shredder/regionExtractor'); + +class PlunkerBuilder { + constructor(basePath, destPath, options) { + this.basePath = basePath; + this.destPath = destPath; + this.options = options; + this.copyrights = {}; + + this._buildCopyrightStrings(); + } + + buildPlunkers() { + this._getPlunkerFiles(); + var errFn = this.options.errFn || function(e) { console.log(e); }; + var plunkerPaths = path.join(this.basePath, '**/*plnkr.json'); + var fileNames = globby.sync(plunkerPaths, { ignore: "**/node_modules/**"}); + fileNames.forEach((configFileName) => { + try { + this._buildPlunkerFrom(configFileName); + } catch (e) { + errFn(e); + } + }); + } + + _addPlunkerFiles(config, postData) { + this._addReadme(config, postData); + if (config.basePath.indexOf('/ts') > -1) { + // uses systemjs.config.js so add plunker version + this.options.addField(postData, 'systemjs.config.js', this.systemjsConfig); + this.options.addField(postData, 'tsconfig.json', this.tsconfig); + } + } + + _addReadme(config, postData) { + var existingFiles = config.fileNames.map(function(file) { + return file.substr(file.lastIndexOf('/') + 1); + }); + + if (existingFiles.indexOf('README.md') === -1) { + var plunkerReadme = this.readme + config.description; + this.options.addField(postData, 'README.md', plunkerReadme); + } + } + + _buildCopyrightStrings() { + var copyright = 'Copyright 2016 Google Inc. All Rights Reserved.\n' + + 'Use of this source code is governed by an MIT-style license that\n' + + 'can be found in the LICENSE file at http://angular.io/license'; + var pad = '\n\n'; + this.copyrights.jsCss = `${pad}/*\n${copyright}\n*/`; + this.copyrights.html = `${pad}`; + } + + // config has + // files: [] - optional array of globs - defaults to all js, ts, html, json, css and md files (with certain files removed) + // description: optional string - description of this plunker - defaults to the title in the index.html page. + // tags: [] - optional array of strings + // main: string - filename of what will become index.html in the plunker - defaults to index.html + _buildPlunkerFrom(configFileName) { + // replace ending 'plnkr.json' with 'plnkr.no-link.html' to create output file name; + var outputFileName = `${this.options.plunkerFileName}.no-link.html`; + outputFileName = configFileName.substr(0, configFileName.length - 'plnkr.json'.length) + outputFileName; + var altFileName; + if (this.destPath && this.destPath.length > 0) { + var partPath = path.dirname(path.relative(this.basePath, outputFileName)); + var altFileName = path.join(this.destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); + } + try { + var config = this._initConfigAndCollectFileNames(configFileName); + var postData = this._createPostData(config); + this._addPlunkerFiles(config, postData); + var html = this._createPlunkerHtml(postData, altFileName); + if (this.options.writeNoLink) { + fs.writeFileSync(outputFileName, html, 'utf-8'); + } + if (altFileName) { + var altDirName = path.dirname(altFileName); + if (!fs.existsSync(altDirName)) { + mkdirp.sync(altDirName); + } + fs.writeFileSync(altFileName, html, 'utf-8'); + } + } catch (e) { + // if we fail delete the outputFile if it exists because it is an old one. + if (this._existsSync(outputFileName)) { + fs.unlinkSync(outputFileName); + } + if (altFileName && this._existsSync(altFileName)) { + fs.unlinkSync(altFileName); + } + throw e; + } + } + + _createBasePlunkerHtml(embedded, altFileName) { + // We extract the filename without extension + var targetName = ''; + if (altFileName) { + targetName = altFileName.split('/').pop().slice(0, -5); + } + var target = embedded ? targetName : '_self'; + var html = '' + html += `
` + + // html += '
' + // html += '
' + html += '' + html += ''; + return html; + } + + _createPostData(config) { + var postData = {}; + config.fileNames.forEach((fileName) => { + var content; + var extn = path.extname(fileName); + if (extn == '.png') { + content = this._encodeBase64(fileName); + fileName = fileName.substr(0, fileName.length - 4) + '.base64.png' + } else { + content = fs.readFileSync(fileName, 'utf-8'); + } + + if (extn == '.js' || extn == '.ts' || extn == '.css') { + content = content + this.copyrights.jsCss; + } else if (extn == '.html') { + content = content + this.copyrights.html; + } + // var escapedValue = escapeHtml(content); + + var relativeFileName = path.relative(config.basePath, fileName); + + if (relativeFileName == config.main) { + relativeFileName = 'index.html'; + } + + if (relativeFileName == 'index.html') { + content = indexHtmlTranslator.translate(content); + if (config.description == null) { + // set config.description to title from index.html + var matches = /(.*)<\/title>/.exec(content); + if (matches) { + config.description = matches[1]; + } + } + } + content = regionExtractor.removeDocTags(content, extn.substr(1)); + + this.options.addField(postData, relativeFileName, content); + }); + + var tags = ['angular2', 'example'].concat(config.tags || []); + tags.forEach(function(tag,ix) { + postData['tags[' + ix + ']'] = tag; + }); + + if (!this.options.embedded) { + postData.private = true; + + postData.description = "Angular 2 Example - " + config.description; + } else { + postData.title = "Angular 2 Example - " + config.description; + } + + // Embedded needs to add more content, so if the callback is available, we call it + if (this.options.extraData) { + this.options.extraData(postData, config); + } + return postData; + } + + _createPlunkerHtml(postData, altFileName) { + var baseHtml = this._createBasePlunkerHtml(this.options.embedded, altFileName); + var doc = jsdom.jsdom(baseHtml); + var form = doc.querySelector('form'); + _.forEach(postData, (value, key) => { + var ele = this._htmlToElement(doc, '<input type="hidden" name="' + key + '">'); + ele.setAttribute('value', value); + form.appendChild(ele) + }); + var html = doc.documentElement.outerHTML; + + return html; + } + + _encodeBase64(file) { + // read binary data + var bitmap = fs.readFileSync(file); + // convert binary data to base64 encoded string + return new Buffer(bitmap).toString('base64'); + } + + _existsSync(filename) { + try { + fs.accessSync(filename); + return true; + } catch(ex) { + return false; + } + } + + _getPlunkerFiles() { + // Assume plunker version is sibling of node_modules version + this.readme = fs.readFileSync(this.basePath + '/plunker.README.md', 'utf-8'); + var systemJsConfigPath = '/systemjs.config.plunker.js'; + if (this.options.build) { + systemJsConfigPath = '/systemjs.config.plunker.build.js'; + } + this.systemjsConfig = fs.readFileSync(this.basePath + systemJsConfigPath, 'utf-8'); + this.systemjsConfig += this.copyrights.jsCss; + this.tsconfig = fs.readFileSync(`${this.basePath}/tsconfig.json`, 'utf-8'); + } + + _htmlToElement(document, html) { + var div = document.createElement('div'); + div.innerHTML = html; + return div.firstChild; + } + + _initConfigAndCollectFileNames(configFileName) { + var basePath = path.dirname(configFileName); + var configSrc = fs.readFileSync(configFileName, 'utf-8'); + try { + var config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; + } catch (e) { + throw new Error(`Plunker config - unable to parse json file: ${configFileName}\n${e}`); + } + + var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; + if (config.files) { + if (config.files.length > 0) { + if (config.files[0].substr(0, 1) == '!') { + config.files = defaultIncludes.concat(config.files); + } + } + } else { + config.files = defaultIncludes; + } + var gpaths = config.files.map(function(fileName) { + fileName = fileName.trim(); + if (fileName.substr(0,1) == '!') { + return "!" + path.join(basePath, fileName.substr(1)); + } else { + return path.join(basePath, fileName); + } + }); + + // var defaultExcludes = [ '!**/node_modules/**','!**/typings/**','!**/tsconfig.json', '!**/*plnkr.json', '!**/*plnkr.html', '!**/*plnkr.no-link.html' ]; + var defaultExcludes = [ + '!**/typings/**', + '!**/typings.json', + '!**/tsconfig.json', + '!**/*plnkr.*', + '!**/package.json', + '!**/example-config.json', + '!**/*.spec.*', + '!**/tslint.json', + '!**/.editorconfig', + '!**/systemjs.config.js', + '!**/wallaby.js', + '!**/karma-test-shim.js', + '!**/karma.conf.js', + '!**/spec.js' + ]; + Array.prototype.push.apply(gpaths, defaultExcludes); + + config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] }); + config.basePath = basePath; + + return config; + } +} + +module.exports = PlunkerBuilder; + +// not currently used. +// function escapeHtml(unsafe) { +// return unsafe +// .replace(/&/g, "&") +// .replace(/</g, "<") +// .replace(/>/g, ">") +// .replace(/"/g, """) +// .replace(/'/g, "'"); +// } + +//// Old version - no longer used +//function createPlunkerHtmlAsync(basePath, postData) { +// +// useNewWindow = false; +// jsdom.env({ +// html: createBasePlunkerHtml(useNewWindow), +// done: function (err, window) { +// var doc = window.document; +// var form = doc.querySelector('form'); +// +// _.forEach(postData, function(value, key) { +// var ele = htmlToElement(doc, '<input type="hidden" name="' + key + '">'); +// ele.setAttribute('value', value); +// form.appendChild(ele) +// }); +// var html = doc.documentElement.outerHTML; +// var outputFn = path.join(basePath, "plnkr.html"); +// fs.writeFileSync(outputFn, html, 'utf-8' ); +// } +// }); +//} diff --git a/tools/plunker-builder/embeddedPlunker.js b/tools/plunker-builder/embeddedPlunker.js new file mode 100644 index 0000000000..6da491702d --- /dev/null +++ b/tools/plunker-builder/embeddedPlunker.js @@ -0,0 +1,34 @@ +var PlunkerBuilder = require('./builder'); + +function buildPlunkers(basePath, destPath, options) { + configureBuilder(options); + var builder = new PlunkerBuilder(basePath, destPath, options); + builder.buildPlunkers(); +} + +function configureBuilder(options) { + options.addField = addField; + options.plunkerFileName = 'eplnkr'; + options.url = 'https://embed.plnkr.co?show=preview'; + options.writeNoLink = false; + options.embedded = true; + options.extraData = extraData; +} + +function extraData(postData, config) { + postData['source[type]'] = config.description || 'Angular 2 example'; + postData['source[url]'] = 'https://angular.io' +} + +function addField(postData, name, content) { + var encoding = 'utf8'; + if (name.split('.').pop === 'png') { + encoding = 'base64'; + } + postData[`entries[${name}][content]`] = content; + postData[`entries[${name}][encoding]`] = encoding; +} + +module.exports = { + buildPlunkers: buildPlunkers +}; diff --git a/tools/plunker-builder/plunkerBuilder.js b/tools/plunker-builder/plunkerBuilder.js deleted file mode 100644 index b2f1a4981d..0000000000 --- a/tools/plunker-builder/plunkerBuilder.js +++ /dev/null @@ -1,309 +0,0 @@ -// Canonical path provides a consistent path (i.e. always forward slashes) across different OSes -var path = require('canonical-path'); -var Q = require('q'); -var _ = require('lodash'); -var jsdom = require("jsdom"); -var fs = require("fs"); -var globby = require('globby'); -var mkdirp = require('mkdirp'); - -var indexHtmlTranslator = require('./indexHtmlTranslator'); -var regionExtractor = require('../doc-shredder/regionExtractor'); -var COPYRIGHT, COPYRIGHT_JS_CSS, COPYRIGHT_HTML; -var README; // content of plunker.README.md for plunkers -var SYSTEMJS_CONFIG; // content of systemjs.config.js for plunkers that use systemjs -var TSCONFIG; // content of tsconfig.json for plunkers that use systemjs - -module.exports = { - buildPlunkers: buildPlunkers -}; - -buildCopyrightStrings(); - -function buildCopyrightStrings() { - var COPYRIGHT = 'Copyright 2016 Google Inc. All Rights Reserved.\n' - + 'Use of this source code is governed by an MIT-style license that\n' - + 'can be found in the LICENSE file at http://angular.io/license'; - var pad = '\n\n'; - COPYRIGHT_JS_CSS = pad + '/*\n' + COPYRIGHT + '\n*/'; - COPYRIGHT_HTML = pad + '<!-- \n' + COPYRIGHT + '\n-->' -} - -function buildPlunkers(basePath, destPath, options) { - getPlunkerFiles(basePath, options); - var errFn = options.errFn || function(e) { console.log(e); }; - var plunkerPaths = path.join(basePath, '**/*plnkr.json'); - var fileNames = globby.sync(plunkerPaths, { ignore: "**/node_modules/**"}); - fileNames.forEach(function(configFileName) { - try { - buildPlunkerFrom(configFileName, basePath, destPath); - } catch (e) { - errFn(e); - } - }); -} - -// config has -// files: [] - optional array of globs - defaults to all js, ts, html, json, css and md files (with certain files removed) -// description: optional string - description of this plunker - defaults to the title in the index.html page. -// tags: [] - optional array of strings -// main: string - filename of what will become index.html in the plunker - defaults to index.html -function buildPlunkerFrom(configFileName, basePath, destPath) { - // replace ending 'plnkr.json' with 'plnkr.no-link.html' to create output file name; - var outputFileName = configFileName.substr(0, configFileName.length - 'plnkr.json'.length) + 'plnkr.no-link.html'; - var altFileName; - if (destPath && destPath.length > 0) { - var partPath = path.dirname(path.relative(basePath, outputFileName)); - var altFileName = path.join(destPath, partPath, path.basename(outputFileName)).replace('.no-link.', '.'); - } - try { - var config = initConfigAndCollectFileNames(configFileName); - var postData = createPostData(config); - addPlunkerFiles(config, postData); - var html = createPlunkerHtml(postData); - fs.writeFileSync(outputFileName, html, 'utf-8'); - if (altFileName) { - var altDirName = path.dirname(altFileName); - if (!fs.existsSync(altDirName)) { - mkdirp.sync(altDirName); - } - fs.writeFileSync(altFileName, html, 'utf-8'); - } - } catch (e) { - // if we fail delete the outputFile if it exists because it is an old one. - if (existsSync(outputFileName)) { - fs.unlinkSync(outputFileName); - } - if (altFileName && existsSync(altFileName)) { - fs.unlinkSync(altFileName); - } - throw e; - } -} - -function addPlunkerFiles(config, postData) { - addReadme(config, postData); - if (config.basePath.indexOf('/ts') > -1) { - // uses systemjs.config.js so add plunker version - postData['files[systemjs.config.js]'] = SYSTEMJS_CONFIG; - postData['files[tsconfig.json]'] = TSCONFIG; - } -} - -function addReadme(config, postData) { - var existingFiles = config.fileNames.map(function(file) { - return file.substr(file.lastIndexOf('/') + 1); - }); - - if (existingFiles.indexOf('README.md') === -1) { - var plunkerReadme = README + config.description; - postData['files[README.md]'] = plunkerReadme; - } -} - -function getPlunkerFiles(basePath, options) { - // Assume plunker version is sibling of node_modules version - README = fs.readFileSync(basePath + '/plunker.README.md', 'utf-8'); - var systemJsConfigPath = '/systemjs.config.plunker.js'; - if (options.build) { - systemJsConfigPath = '/systemjs.config.plunker.build.js'; - } - SYSTEMJS_CONFIG = fs.readFileSync(basePath + systemJsConfigPath, 'utf-8'); - SYSTEMJS_CONFIG += COPYRIGHT_JS_CSS; - TSCONFIG = fs.readFileSync(basePath + '/tsconfig.json', 'utf-8'); -} - -function initConfigAndCollectFileNames(configFileName) { - var basePath = path.dirname(configFileName); - var configSrc = fs.readFileSync(configFileName, 'utf-8'); - try { - var config = (configSrc && configSrc.trim().length) ? JSON.parse(configSrc) : {}; - } catch (e) { - throw new Error("Plunker config - unable to parse json file: " + configFileName + '\n ' + e); - } - - var defaultIncludes = ['**/*.ts', '**/*.js', '**/*.css', '**/*.html', '**/*.md', '**/*.json', '**/*.png']; - if (config.files) { - if (config.files.length > 0) { - if (config.files[0].substr(0, 1) == '!') { - config.files = defaultIncludes.concat(config.files); - } - } - } else { - config.files = defaultIncludes; - } - var gpaths = config.files.map(function(fileName) { - fileName = fileName.trim(); - if (fileName.substr(0,1) == '!') { - return "!" + path.join(basePath, fileName.substr(1)); - } else { - return path.join(basePath, fileName); - } - }); - - // var defaultExcludes = [ '!**/node_modules/**','!**/typings/**','!**/tsconfig.json', '!**/*plnkr.json', '!**/*plnkr.html', '!**/*plnkr.no-link.html' ]; - var defaultExcludes = [ - '!**/typings/**', - '!**/typings.json', - '!**/tsconfig.json', - '!**/*plnkr.*', - '!**/package.json', - '!**/example-config.json', - '!**/*.spec.*', - '!**/tslint.json', - '!**/.editorconfig', - '!**/systemjs.config.js', - '!**/wallaby.js', - '!**/karma-test-shim.js', - '!**/karma.conf.js', - '!**/spec.js' - ]; - Array.prototype.push.apply(gpaths, defaultExcludes); - - config.fileNames = globby.sync(gpaths, { ignore: ["**/node_modules/**"] }); - config.basePath = basePath; - - return config; -} - -function createPostData(config) { - var postData = {}; - config.fileNames.forEach(function(fileName) { - var content; - var extn = path.extname(fileName); - if (extn == '.png') { - content = encodeBase64(fileName); - fileName = fileName.substr(0, fileName.length - 4) + '.base64.png' - } else { - content = fs.readFileSync(fileName, 'utf-8'); - } - - if (extn == '.js' || extn == '.ts' || extn == '.css') { - content = content + COPYRIGHT_JS_CSS; - } else if (extn == '.html') { - content = content + COPYRIGHT_HTML; - } - // var escapedValue = escapeHtml(content); - - var relativeFileName = path.relative(config.basePath, fileName); - - if (relativeFileName == config.main) { - relativeFileName = 'index.html'; - } - - if (relativeFileName == 'index.html') { - content = indexHtmlTranslator.translate(content); - if (config.description == null) { - // set config.description to title from index.html - var matches = /<title>(.*)<\/title>/.exec(content); - if (matches) { - config.description = matches[1]; - } - } - } - content = regionExtractor.removeDocTags(content, extn.substr(1)); - - postData['files[' + relativeFileName + ']'] = content; - }); - - // Leave here in case we want to add a md file later. - // postData['files[license.md]'] = fs.readFileSync(path.join(__dirname, "license.md")); - - var tags = ['angular2', 'example'].concat(config.tags || []); - tags.forEach(function(tag,ix) { - postData['tags[' + ix + ']'] = tag; - }); - // postData['tags[0]'] = "angular2"; - // postData['tags[1]'] = "example"; - postData.private = true; - - postData.description = "Angular 2 Example - " + config.description; - return postData; -} - -function existsSync(filename) { - try { - fs.accessSync(filename); - return true; - } catch(ex) { - return false; - } -} - -function encodeBase64(file) { - // read binary data - var bitmap = fs.readFileSync(file); - // convert binary data to base64 encoded string - return new Buffer(bitmap).toString('base64'); -} - -function createPlunkerHtml(postData) { - var baseHtml = createBasePlunkerHtml(false); - var doc = jsdom.jsdom(baseHtml); - var form = doc.querySelector('form'); - _.forEach(postData, function(value, key) { - var ele = htmlToElement(doc, '<input type="hidden" name="' + key + '">'); - ele.setAttribute('value', value); - form.appendChild(ele) - }); - var html = doc.documentElement.outerHTML; - - return html; -} - - -function createBasePlunkerHtml(useNewWindow) { - var url = 'http://plnkr.co/edit/?p=preview'; - // If the form posts to target="_blank", pop-up blockers can cause it not to work. - // If a user choses to bypass pop-up blocker one time and click the link, they will arrive at - // a new default plnkr, not a plnkr with the desired template. Given this undesired behavior, - // some may still want to open the plnk in a new window by opting-in via ctrl+click. The - // newWindow param allows for this possibility. - var target = useNewWindow ? '_blank' : '_self'; - var html = '<!DOCTYPE html><html lang="en"><body>' - html += '<form id="mainForm" method="post" action="' + url + '" target="' + target + '">' - - // html += '<div class="button"><button id="formButton" type="submit">Create Plunker</button></div>' - // html += '</form><script>document.getElementById("formButton").click();</script>' - html += '</form><script>document.getElementById("mainForm").submit();</script>' - html += '</body></html>'; - return html; -} - -function htmlToElement(document, html) { - var div = document.createElement('div'); - div.innerHTML = html; - return div.firstChild; -} - -// not currently used. -function escapeHtml(unsafe) { - return unsafe - .replace(/&/g, "&") - .replace(/</g, "<") - .replace(/>/g, ">") - .replace(/"/g, """) - .replace(/'/g, "'"); -} - -//// Old version - no longer used -//function createPlunkerHtmlAsync(basePath, postData) { -// -// useNewWindow = false; -// jsdom.env({ -// html: createBasePlunkerHtml(useNewWindow), -// done: function (err, window) { -// var doc = window.document; -// var form = doc.querySelector('form'); -// -// _.forEach(postData, function(value, key) { -// var ele = htmlToElement(doc, '<input type="hidden" name="' + key + '">'); -// ele.setAttribute('value', value); -// form.appendChild(ele) -// }); -// var html = doc.documentElement.outerHTML; -// var outputFn = path.join(basePath, "plnkr.html"); -// fs.writeFileSync(outputFn, html, 'utf-8' ); -// } -// }); -//} diff --git a/tools/plunker-builder/regularPlunker.js b/tools/plunker-builder/regularPlunker.js new file mode 100644 index 0000000000..7dda2fa7c0 --- /dev/null +++ b/tools/plunker-builder/regularPlunker.js @@ -0,0 +1,23 @@ +var PlunkerBuilder = require('./builder'); + +function buildPlunkers(basePath, destPath, options) { + configureBuilder(options); + var builder = new PlunkerBuilder(basePath, destPath, options); + builder.buildPlunkers(); +} + +function configureBuilder(options) { + options.addField = addField; + options.plunkerFileName = 'plnkr'; + options.url = 'http://plnkr.co/edit/?p=preview'; + options.writeNoLink = true; + options.embedded = false; +} + +function addField(postData, name, content) { + postData[`files[${name}]`] = content; +} + +module.exports = { + buildPlunkers: buildPlunkers +};