diff --git a/examples/coding-template/Example-Template.html b/examples/coding-template/Example-Template.html
index f5b5c932eb..ef7cc2ff64 100644
--- a/examples/coding-template/Example-Template.html
+++ b/examples/coding-template/Example-Template.html
@@ -57,7 +57,9 @@
EXAMPLE_NAME Example
- Example
+
-
+
-
CSS:
example_name.css
@@ -212,7 +214,7 @@
HTML Source Code
If you change the ID of either the 'ex1' div or the 'sc1' pre, be sure to update the sourceCode.add function parameters.
-->
diff --git a/examples/css/core.css b/examples/css/core.css
index 2179ae63f4..3ce62a3541 100644
--- a/examples/css/core.css
+++ b/examples/css/core.css
@@ -40,3 +40,72 @@ table.data.attributes tbody th,
table.data.attributes tbody td {
border: 1px solid silver;
}
+
+/* CodePen button */
+.example-header {
+ display: flex;
+ align-items: center;
+ margin-top: 3rem;
+ page-break-after: avoid;
+ page-break-inside: avoid;
+ font: 100% sans-serif;
+ font-family: inherit;
+ line-height: 1.2;
+ hyphens: manual;
+}
+
+.example-header > :first-child {
+ margin: 0;
+}
+
+.example-header > :first-child + * {
+ margin-left: 1em;
+}
+
+.example-header button {
+ display: inline-block;
+ position: relative;
+ padding: 0.4em 0.7em;
+ border: 1px solid hsl(213, 71%, 49%);
+ border-radius: 5px;
+ box-shadow: 0 1px 2px hsl(216, 27%, 55%);
+ color: #fff;
+ font-size: inherit;
+ text-shadow: 0 -1px 1px hsl(216, 27%, 25%);
+ background-color: hsl(216, 82%, 51%);
+ background-image: linear-gradient(to bottom, hsl(216, 82%, 53%), hsl(216, 82%, 47%));
+}
+
+.example-header button:hover {
+ border-color: hsl(213, 71%, 29%);
+ background-color: hsl(216, 82%, 31%);
+ background-image: linear-gradient(to bottom, hsl(216, 82%, 33%), hsl(216, 82%, 27%));
+ cursor: default;
+}
+
+.example-header button:focus {
+ outline: none;
+}
+
+.example-header button:focus::before {
+ position: absolute;
+ z-index: -1;
+
+ /* button border width - outline width - offset */
+ top: calc(-1px - 3px - 3px);
+ right: calc(-1px - 3px - 3px);
+ bottom: calc(-1px - 3px - 3px);
+ left: calc(-1px - 3px - 3px);
+ border: 3px solid hsl(213, 71%, 49%);
+
+ /* button border radius + outline width + offset */
+ border-radius: calc(5px + 3px + 3px);
+ content: '';
+}
+
+.example-header button:active {
+ border-color: hsl(213, 71%, 49%);
+ background-color: hsl(216, 82%, 31%);
+ background-image: linear-gradient(to bottom, hsl(216, 82%, 53%), hsl(216, 82%, 47%));
+ box-shadow: inset 0 3px 5px 1px hsl(216, 82%, 30%);
+}
diff --git a/examples/js/examples.js b/examples/js/examples.js
index d0a2c21a20..10aa54ba6f 100644
--- a/examples/js/examples.js
+++ b/examples/js/examples.js
@@ -35,17 +35,26 @@ var VOID_ELEMENTS = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',
aria.widget.SourceCode = function () {
this.location = new Array();
this.code = new Array();
+ this.exampleHeader = new Array();
+ this.resources = new Array();
};
/**
* Adds source code
*
+ * @param {string} locationId - ID of `code` element that will display the example html
+ * @param {string} codeID - ID of element containing only and all of the html used to render the example widget
+ * @param {string} exampleHeaderId - ID of header element under which the "Open in Codepen" button belongs
+ * @param {string} cssJsFilesId - ID of element containing links to all the relevent js and css files used for the example widget
+ *
* @method add
* @memberof aria.widget.SourceCode
*/
-aria.widget.SourceCode.prototype.add = function (locationId, codeId) {
+aria.widget.SourceCode.prototype.add = function (locationId, codeId, exampleHeaderId, cssJsFilesId) {
this.location[this.location.length] = locationId;
this.code[this.code.length] = codeId;
+ this.exampleHeader[this.exampleHeader.length] = exampleHeaderId;
+ this.resources[this.resources.length] = cssJsFilesId;
};
/**
@@ -66,6 +75,11 @@ aria.widget.SourceCode.prototype.make = function () {
if (sourceCodeNode.innerHTML.startsWith('
')) {
sourceCodeNode.innerHTML = sourceCodeNode.innerHTML.replace('
', '');
}
+
+ // Adds the "Open In CodePen" button by the example header
+ if (this.exampleHeader[i]) {
+ addOpenInCodePenForm(i, this.exampleHeader[i], this.code[i], this.resources[i]);
+ }
}
};
@@ -300,4 +314,96 @@ function indentLines (input, indentation) {
return lines.join('\n');
}
+/**
+ * Creates and adds an "Open in CodePen" button
+ *
+ * @param {String} exampleIndex - the example number, if there are multiple examples
+ * @param {String} exampleHeaderId - the example header to place the button next to
+ * @param {String} exampleCodeId - the example html code
+ * @param {String} exampleFilesId - the element containing all relevent CSS and JS file
+ */
+function addOpenInCodePenForm (exampleIndex, exampleHeaderId, exampleCodeId, exampleFilesId) {
+ var jsonInputId = 'codepen-data-ex-' + exampleIndex;
+ var buttonId = exampleCodeId + '-codepenbutton'
+
+ var form = document.createElement('form');
+ form.setAttribute('action', 'https://codepen.io/pen/define');
+ form.setAttribute('method', 'POST');
+ form.setAttribute('target', '_blank');
+
+ var input = document.createElement('input');
+ input.setAttribute('id', jsonInputId);
+ input.setAttribute('type', 'hidden');
+ input.setAttribute('name', 'data');
+
+ var button = document.createElement('button');
+ button.innerText = 'Open In CodePen';
+
+ form.appendChild(input);
+ form.appendChild(button);
+
+ var exampleHeader = document.getElementById(exampleHeaderId);
+ exampleHeader.parentNode.insertBefore(form, exampleHeader.nextSibling);
+
+ // Correct the indentation for the example html
+ var indentedExampleHtml = document.getElementById(exampleCodeId).innerHTML;
+ indentedExampleHtml = indentedExampleHtml.replace(/^\n+/, '');
+ var indentation = indentedExampleHtml.match(/^\s+/)[0];
+ var exampleHtml = indentedExampleHtml.replace(new RegExp('^' + indentation, 'gm'), '');
+
+ var postJson = {
+ html: exampleHtml,
+ css: '',
+ js: '',
+ head: ''
+ };
+
+ var totalFetchedFiles = 0;
+ var fileLinks = document.querySelectorAll('#' + exampleFilesId + ' a');
+
+ for (let fileLink of fileLinks) {
+
+ var request = new XMLHttpRequest();
+
+ request.open('GET', fileLink.href, true);
+ request.onload = function() {
+ var href = this.responseURL;
+ if (this.status >= 200 && this.status < 400) {
+ if (href.indexOf('css') !== -1) {
+ postJson.css = postJson.css.concat(this.response);
+ }
+ if (href.indexOf('js') !== -1) {
+ postJson.js = postJson.js.concat(this.response);
+ }
+ totalFetchedFiles++;
+ }
+ else {
+ hideButton(buttonId, "Could not load resource: " + href);
+ }
+ };
+ request.onerror = function() {
+ hideButton(buttonId, "Could not load resource: " + fileLink.href);
+ };
+ request.send();
+ }
+
+ var timerId = setInterval(() => {
+ console.log(totalFetchedFiles);
+ if (totalFetchedFiles === fileLinks.length) {
+ document.getElementById(jsonInputId).value = JSON.stringify(postJson);
+ clearInterval(timerId);
+ }
+ }, 500);
+
+ setTimeout(() => {
+ clearInterval(timerId);
+ }, 10000);
+}
+
+function hideButton(buttonId, errorMsg) {
+ let button = document.querySelector(buttonId);
+ button.style.display = "none";
+ console.log("Removing 'Open in Codepen button'. " + errorMsg);
+}
+
var sourceCode = new aria.widget.SourceCode();