forked from angular/material
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(docs): edit code example in codepen
* add support for running specs in docs * create service that converts docs demo information to a new codepen. * all other demos use icons/images located in docs/app/img/icons or docs/app/img * asset cache is required to serve SVG images on codepen. * This script allows collaborators to regenerate the assetMap JSON located in the asset-cache.js file. * add button to each example to open the example in codepen to edit. * ng-app attribute is appended to a parent element in the docs site, and is appended to the parent element of the index.html file when sending to codepen. * need to send full path to codepen in order to retrieve the asset. * use <code> block around code docs * register icon sets inside demo * .sample is not included in the example html sent to codepen. * add documentation for codepen usage * Conflicts with karma port defined for core material design * compress codepen logo * add comment to describe karma-docs * improve documentation of functions * use ng-src instead of src * document build-asset-cache.sh * add docs for building hidden form * remove aria-label from codepen button * hide examples that are not editable * All the layout examples are not defined with js/css files. This departs from how component examples work. * hide edit on codepen for small layout Closes angular#2604. Closes angular#2757.
- Loading branch information
1 parent
4de34f8
commit 5c37dc8
Showing
47 changed files
with
763 additions
and
118 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Used for running unit tests against the docs site | ||
// Unit tests can be run using gulp docs-karma | ||
module.exports = function(config) { | ||
|
||
var UNCOMPILED_SRC = [ | ||
'docs/spec/**/*.spec.js' | ||
]; | ||
|
||
// releaseMode is a custom configuration option. | ||
var testSrc = UNCOMPILED_SRC; | ||
var dependencies = process.env.KARMA_TEST_JQUERY ? | ||
['node_modules/jquery/dist/jquery.js'] : []; | ||
|
||
dependencies = dependencies.concat([ | ||
'node_modules/angular/angular.js', | ||
'node_modules/angular-animate/angular-animate.js', | ||
'node_modules/angular-aria/angular-aria.js', | ||
'node_modules/angular-messages/angular-messages.js', | ||
'node_modules/angular-route/angular-route.js', | ||
'node_modules/angular-mocks/angular-mocks.js', | ||
'dist/angular-material.js', | ||
'config/test-utils.js', | ||
'dist/docs/docs.js', | ||
'dist/docs/docs-demo-scripts.js' | ||
]); | ||
|
||
config.set({ | ||
|
||
basePath: __dirname + '/..', | ||
frameworks: ['jasmine'], | ||
files: dependencies.concat(testSrc), | ||
|
||
port: 9877, | ||
reporters: ['progress'], | ||
colors: true, | ||
|
||
// Continuous Integration mode | ||
// enable / disable watching file and executing tests whenever any file changes | ||
autoWatch: false, | ||
singleRun: false, | ||
|
||
// Start these browsers, currently available: | ||
// - Chrome | ||
// - ChromeCanary | ||
// - Firefox | ||
// - Opera (has to be installed with `npm install karma-opera-launcher`) | ||
// - Safari (only Mac; has to be installed with `npm install karma-safari-launcher`) | ||
// - PhantomJS | ||
// - IE (only Windows; has to be installed with `npm install karma-ie-launcher`) | ||
browsers: ['Chrome'] | ||
}); | ||
|
||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
File renamed without changes
File renamed without changes
File renamed without changes
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
(function() { | ||
DocsApp | ||
.factory('codepenDataAdapter', CodepenDataAdapter) | ||
.factory('codepen', ['$demoAngularScripts', '$document', 'codepenDataAdapter', Codepen]); | ||
|
||
// Provides a service to open a code example in codepen. | ||
function Codepen($demoAngularScripts, $document, codepenDataAdapter) { | ||
|
||
var CODEPEN_API = 'http://codepen.io/pen/define/'; | ||
|
||
return { | ||
editOnCodepen: editOnCodepen | ||
}; | ||
|
||
// Creates a codepen from the given demo model by posting to Codepen's API | ||
// using a hidden form. The hidden form is necessary to avoid a CORS issue. | ||
// See http://blog.codepen.io/documentation/api/prefill | ||
function editOnCodepen(demo) { | ||
var data = codepenDataAdapter.translate(demo, $demoAngularScripts.all()); | ||
var form = buildForm(data); | ||
$document.find('body').append(form); | ||
form[0].submit(); | ||
form.remove(); | ||
} | ||
|
||
// Builds a hidden form with data necessary to create a codepen. | ||
function buildForm(data) { | ||
var form = angular.element( | ||
'<form style="display: none;" method="post" target="_blank" action="' + | ||
CODEPEN_API + | ||
'"></form>' | ||
); | ||
var input = '<input type="hidden" name="data" value="' + escapeJsonQuotes(data) + '" />'; | ||
form.append(input); | ||
return form; | ||
} | ||
|
||
// Recommended by Codepen to escape quotes. | ||
// See http://blog.codepen.io/documentation/api/prefill | ||
function escapeJsonQuotes(json) { | ||
return JSON.stringify(json) | ||
.replace(/"/g, """) | ||
.replace(/"/g, "'"); | ||
} | ||
} | ||
|
||
// Translates demo metadata and files into Codepen's post form data. See api documentation for | ||
// additional fields not used by this service. http://blog.codepen.io/documentation/api/prefill | ||
function CodepenDataAdapter() { | ||
|
||
var CORE_JS = 'https://cdn.rawgit.com/angular/bower-material/master/angular-material.js'; | ||
var CORE_CSS = 'https://cdn.rawgit.com/angular/bower-material/master/angular-material.css'; | ||
var ASSET_CACHE_JS = 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/t-114/assets-cache.js'; | ||
|
||
return { | ||
translate: translate | ||
}; | ||
|
||
// Translates a demo model to match Codepen's post data | ||
// See http://blog.codepen.io/documentation/api/prefill | ||
function translate(demo, externalScripts) { | ||
var files = demo.files; | ||
|
||
return { | ||
title: demo.title, | ||
html: processHtml(demo), | ||
css: mergeFiles(files.css).join(' '), | ||
js: processJs(files.js), | ||
js_external: externalScripts.concat([CORE_JS, ASSET_CACHE_JS]).join(';'), | ||
css_external: CORE_CSS | ||
}; | ||
} | ||
|
||
// Modifies index.html with neccesary changes in order to display correctly in codepen | ||
// See each processor to determine how each modifies the html | ||
function processHtml(demo) { | ||
var index = demo.files.index.contents; | ||
|
||
var processors = [ | ||
applyAngularAttributesToParentElement, | ||
insertTemplatesAsScriptTags, | ||
htmlEscapeAmpersand | ||
]; | ||
|
||
processors.forEach(function(processor) { | ||
index = processor(index, demo); | ||
}); | ||
|
||
return index; | ||
} | ||
|
||
// Applies modifications the javascript prior to sending to codepen. | ||
// Currently merges js files and replaces the module with the Codepen | ||
// module. See documentation for replaceDemoModuleWithCodepenModule. | ||
function processJs(jsFiles) { | ||
var mergedJs = mergeFiles(jsFiles).join(' '); | ||
var script = replaceDemoModuleWithCodepenModule(mergedJs); | ||
return script; | ||
} | ||
|
||
// Maps file contents to an array | ||
function mergeFiles(files) { | ||
return files.map(function(file) { | ||
return file.contents; | ||
}); | ||
} | ||
|
||
// Adds class to parent element so that styles are applied correctly | ||
// Adds ng-app attribute. This is the same module name provided in the asset-cache.js | ||
function applyAngularAttributesToParentElement(html, demo) { | ||
var tmp; | ||
|
||
// Grab only the DIV for the demo... | ||
angular.forEach(angular.element(html), function(it,key){ | ||
if ((it.nodeName != "SCRIPT") || (it.nodeName != "#text")) { | ||
tmp = angular.element(it); | ||
} | ||
}); | ||
|
||
tmp.addClass(demo.id); | ||
tmp.attr('ng-app', 'MyApp'); | ||
return tmp[0].outerHTML; | ||
} | ||
|
||
// Adds templates inline in the html, so that templates are cached in the example | ||
function insertTemplatesAsScriptTags(indexHtml, demo) { | ||
if (demo.files.html.length) { | ||
var tmp = angular.element(indexHtml); | ||
angular.forEach(demo.files.html, function(template) { | ||
tmp.append("<script type='text/ng-template' id='" + | ||
template.name + "'>" + | ||
template.contents + | ||
"</script>"); | ||
}); | ||
return tmp[0].outerHTML; | ||
} | ||
return indexHtml; | ||
} | ||
|
||
// Escapes ampersands so that after codepen unescapes the html the escaped code block | ||
// uses the correct escaped characters | ||
function htmlEscapeAmpersand(html) { | ||
return html | ||
.replace(/>/g, "&gt;") | ||
.replace(/</g, "&lt;"); | ||
} | ||
|
||
// Required to make codepen work. Demos define their own module when running on the | ||
// docs site. In order to ensure the codepen example can use the asset-cache, the | ||
// module needs to match so that the $templateCache is populated with the necessary | ||
// assets. | ||
function replaceDemoModuleWithCodepenModule(file) { | ||
var matchAngularModule = /\.module\(('[^']*'|"[^"]*")\s*,(?:\s*\[([^\]]*)\])?/g; | ||
return file.replace(matchAngularModule, ".module('MyApp'"); | ||
} | ||
} | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
(function() { | ||
DocsApp | ||
.factory('$demoAngularScripts', ['BUILDCONFIG', DemoAngularScripts]); | ||
|
||
function DemoAngularScripts(BUILDCONFIG) { | ||
var scripts = [ | ||
'angular.js', | ||
'angular-animate.min.js', | ||
'angular-route.min.js', | ||
'angular-aria.min.js', | ||
'angular-messages.min.js' | ||
]; | ||
|
||
return { | ||
all: allAngularScripts | ||
}; | ||
|
||
function allAngularScripts() { | ||
return scripts.map(fullPathToScript); | ||
}; | ||
|
||
function fullPathToScript(script) { | ||
return "https://ajax.googleapis.com/ajax/libs/angularjs/" + BUILDCONFIG.ngVersion + "/" + script; | ||
}; | ||
}; | ||
})(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# Editable Demos in Codepen | ||
|
||
## Description | ||
|
||
Users will be able to click a button on each demo to open in codepen | ||
to edit. From there the user can edit, save or make other | ||
modifications to the example. | ||
|
||
## Why Codepen? | ||
|
||
Codepen appears to be one the most stable and active online sandboxes. | ||
It has less accessibility problems then some of the other tools. | ||
|
||
## How does it work? | ||
|
||
When the user clicks on the **'Edit on codepen'** button, all files including | ||
html, css, js, templates are used to create the new codepen by posting | ||
to the [Codepen API](http://blog.codepen.io/documentation/api/prefill/). An | ||
additional script is appended to the example to initialize the | ||
[cache](#asset_cache), which is responsible for serving assets. | ||
|
||
## As a contributor, what do I need to know? | ||
|
||
* [SVG images are served from a cache](#asset_cache) | ||
* [Adding a new SVG requires a change to the asset cache](#build_cache) | ||
* Anytime a new dependency is added to an example, the [asset-cache.js](../app/asset-cache.js) | ||
will need to be updated with the new dependency and [uploaded to the | ||
CDN](#update_cdn) | ||
* Images used in demos must use full paths | ||
* Code examples are modified prior to sending to codepen with the same | ||
module defined in the [asset-cache.js](../app/asset-cache.js) | ||
* Additional HTML template files located in the demo directory are appended to your index file using `ng-template`. [See docs](https://docs.angularjs.org/api/ng/directive/script) | ||
|
||
## <a name="asset_cache"></a> Asset Cache | ||
|
||
SVG images are stored in an asset cache using `$templateCache`. A | ||
script is delivered to codepen that initializes the cache within the | ||
demo module. | ||
|
||
### Why is an asset cache needed for Codepen? | ||
|
||
Components within angular material at times use icons or SVG. Images | ||
are fetched over http. Without having a server that will allow cross | ||
site scripting (`Access-Control-Allow-Origin: *`), the request will | ||
fail with a [CORS](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS) | ||
error. | ||
|
||
The asset cache is intended to bypass any http request for an image | ||
and serve the cached content. | ||
|
||
### <a name="build_cache"></a> How do I populate the cache? | ||
|
||
* Make all changes necessary to add or update any svg images | ||
* run `./scripts/build-asset-cache.sh | pbcopy` to add an object | ||
literal to your paste buffer. | ||
* paste object literal as `var assetMap = { ... }` in the | ||
[asset-cache.js](../app/asset-cache.js) | ||
* [update](#build_cdn) the CDN with the new script | ||
* commit asset-cache.js | ||
|
||
### <a name="update_cdn"></a> Update Codepen Asset Cache | ||
|
||
CDN is located on the Codepen PRO account. | ||
|
||
* Follow the [instructions](http://blog.codepen.io/documentation/pro-features/asset-hosting/#asset-manager) on how to update the script. | ||
* NOTE: be sure to update the script. DO NOT upload a new script. The URL should remain the same | ||
|
||
## Deployment Considerations | ||
|
||
The step to generate and deploy the asset-cache.js is currently a | ||
manual process. Keep in mind that if changes are made to | ||
asset-cache.js then you will need to follow the [steps](#update_cdn) | ||
to update the cache on the CDN. |
Oops, something went wrong.