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 0000000000..becea3bab3
Binary files /dev/null and b/public/resources/images/plunker/placeholder.png differ
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 '' +
+ '' +
+ '
' +
+ '';
+ }
+
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 += '';
+ 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, '');
+ 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, "'");
+// }
+
+//// 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, '');
+// 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 + ''
-}
-
-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>/.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, '');
- 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 = ''
- html += ''
- html += ''
- 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, "'");
-}
-
-//// 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, '');
-// 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
+};