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

+
+

Example

+
-
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();