HTML preprocessors can make writing HTML more powerful or convenient. For instance, Markdown is designed to be easier to write and read for text documents and you could write a loop in Pug.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. So you don't have access to higher-up elements like the <html>
tag. If you want to add classes there that can affect the whole document, this is the place to do it.
In CodePen, whatever you write in the HTML editor is what goes within the <body>
tags in a basic HTML5 template. If you need things in the <head>
of the document, put that code here.
The resource you are linking to is using the 'http' protocol, which may not work when the browser is using https.
CSS preprocessors help make authoring CSS easier. All of them offer things like variables and mixins to provide convenient abstractions.
It's a common practice to apply CSS to a page that styles elements such that they are consistent across all browsers. We offer two of the most popular choices: normalize.css and a reset. Or, choose Neither and nothing will be applied.
To get the best cross-browser support, it is a common practice to apply vendor prefixes to CSS properties and values that require them to work. For instance -webkit-
or -moz-
.
We offer two popular choices: Autoprefixer (which processes your CSS server-side) and -prefix-free (which applies prefixes via a script, client-side).
Any URLs added here will be added as <link>
s in order, and before the CSS in the editor. You can use the CSS from another Pen by using its URL and the proper URL extension.
You can apply CSS to your Pen from any stylesheet on the web. Just put a URL to it here and we'll apply it, in the order you have them, before the CSS in the Pen itself.
You can also link to another Pen here (use the .css
URL Extension) and we'll pull the CSS from that Pen and include it. If it's using a matching preprocessor, use the appropriate URL Extension and we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
JavaScript preprocessors can help make authoring JavaScript easier and more convenient.
Babel includes JSX processing.
Any URL's added here will be added as <script>
s in order, and run before the JavaScript in the editor. You can use the URL of any other Pen and it will include the JavaScript from that Pen.
You can apply a script from anywhere on the web to your Pen. Just put a URL to it here and we'll add it, in the order you have them, before the JavaScript in the Pen itself.
If the script you link to has the file extension of a preprocessor, we'll attempt to process it before applying.
You can also link to another Pen here, and we'll pull the JavaScript from that Pen and include it. If it's using a matching preprocessor, we'll combine the code before preprocessing, so you can use the linked Pen as a true dependency.
Search for and use JavaScript packages from npm here. By selecting a package, an import
statement will be added to the top of the JavaScript editor for this package.
Using packages here is powered by Skypack, which makes packages from npm not only available on a CDN, but prepares them for native JavaScript ES6 import
usage.
All packages are different, so refer to their docs for how they work.
If you're using React / ReactDOM, make sure to turn on Babel for the JSX processing.
If active, Pens will autosave every 30 seconds after being saved once.
If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.
If enabled, your code will be formatted when you actively save your Pen. Note: your code becomes un-folded during formatting.
Visit your global Editor Settings.
<div id="css-table">
<div id="col-1">
<ul>
<li><a href="#col-1-tab-1">Example 6<br> </a></li>
</ul>
<div id="col-1-tab-1">
<article>
<h1>matched pairs—recursion</h1>
<p class="title">
<b>pattern syntax:</b>
</p>
<textarea id="syntax" wrap="off"></textarea>
<p class="title">
<b>input string:</b>
</p>
<textarea id="input" wrap="off"></textarea>
<p>
<button id="exec" value="exec">exec()</button>
</p>
</article>
</div>
</div>
<div id="col-2">
<ul>
<li><a href="#col-2-tab-1">matched<br>pairs
</a></li>
<li><a href="#col-2-tab-2">unmatched<br>pairs
</a></li>
<li><a href="#col-2-tab-3">internal<br>pairs
</a></li>
<li><a href="#col-2-tab-4">inserted<br>text
</a></li>
<li><a href="#col-2-tab-5">HTML<br>tags
</a></li>
</ul>
<div id="col-2-tab-1">
<article>
<div class="example">
<div class="discuss">
<p>
This is the basic pattern syntax for matching nested pairs.
<code>L</code>
and
<code>R</code>
can be most anything as long as the
<code>L</code>
rule can't match any of the same phrases as the
<code>R</code>
rule.
</p>
<p>
Try changing the parentheses,
<code>()</code>
to brackets
<code>{}</code>
.<br>
<button id="matched-brackets">do it</button>
for me.
</p>
<p>
Or even something more complicated.<br>
<button id="matched-html-comments">do it</button>
for me.
</p>
</div>
<div id="matched-here" class="result"></div>
</div>
</article>
</div>
<div id="col-2-tab-2">
<article>
<div class="example">
<div class="discuss">
<p>What happens if the brackets are not matched? If you were adventurous with the previous tab you might have seen
this already. But try it with some unbalanced pairs.</p>
<p>
If the parentheses are just unbalanced it will find the longest match to the first occurrence of any matched pairs.<br>
<button id="long-unbalanced">do it</button>
for me.
</p>
<p>
But if there are no matched pairs at all—out of luck.<br>
<button id="no-pairs">do it</button> for me.
</p>
<p>Often you will want to succeed only if the entire string is balanced.
For that we need use anchors to match the beginning and
ending of the string as well.<br>
<button id="anchors-unmatched">do it</button> with unmatched pairs.<br>
<button id="anchors-matched">do it</button> with matched pairs.
</p>
</div>
<div id="unmatched-here" class="result"></div>
</div>
</article>
</div>
<div id="col-2-tab-3">
<article>
<div class="example">
<div class="discuss">
<p>In case you haven't noticed it yet, the simple formula for balancing matched pairs is missing something important.
The parentheses set up here are nested with equal numbers of left and right parentheses. But you don't get a match to
the entire string. It misses the internal pairs.</p>
<p>
To match pairs within pairs we need a slight modification. Between left and right we need to match <i>one or more</i>
pairs. That looks like this:<br>
<button id="internal">do it</button>
for me.
</p>
<p>
As long as the numbers of left and right parentheses are the same, it should work.<br>
<button id="internal-more">do it</button>
again.
</p>
</div>
<div id="internal-here" class="result"></div>
</div>
</article>
</div>
<div id="col-2-tab-4">
<article>
<div class="example">
<div class="discuss">
<p>Now that you've got matching of paired brackets its a fairly easy matter to insert text between the brackets. You
want to allow text after the left and before right brackets.
The text is optional and can be most anything you like as long as it can't match either of the brackets.
Here text is any printing ASCII characters except the brackets themselves.
</p>
<p>
But if you really need a bracket in your text, with just a little extra effort you can escape it.
Here I've escaped it with the backslash, <code>\</code>, character.<br>
<button id="escape-it">do it</button> escape it for me.
</p>
<p>
or quote it:<br>
<button id="quote-it">do it</button>
quote it for me.
</p>
<p>Note that with both the escaped and quoted text it is important to put them as the first alternate characters.
Don't forget the first-match-wins rule.</p>
</div>
<div id="text-here" class="result"></div>
</div>
</article>
</div>
<div id="col-2-tab-5">
<article>
<div class="example">
<div class="discuss">
<p>
If you have been following along with the previous tabbed examples, it is just a short step to match HTML tags. I'll
keep it simple here, not allowing for attributes, self-closing tags or specific tag names. Also, the text between tags
cannot contain the
<code><</code>
character and no provisions are made to escape it. I just want a demonstration of the basics without obscuring them with
too many details.
</p>
<p>
I'm sure you will have noticed by now that there is no check that the name in a closing tag matches that of
its paired, opening tag. That's a toughy. It requires some advanced features, but it can be done with <b>apg-exp</b>
and here it is.<br>
<button id="parent-mode">show me</button>
</p>
Don't believe it? Try it again with tag names that don't match.<br>
<button id="parent-mode2">try it</button> now.
<p>
</p>
I haven't talked about back references or parent-mode.
You need them both for this example.
But if you are interested in the details, check out the references in the "Where to Go Next" section.
<p>
</p>
</div>
<div id="html-tags-here" class="result"></div>
</div>
</article>
</div>
</div>
</div>
/* Pen-specific styles */
* {
box-sizing: border-box;
}
body {
color: #000;
font-size: .8rem;
line-height: 150%;
}
h1 {
font-size: 1.75rem;
margin: 0 0 0.75rem 0;
font-family: 'Open Sans', sans-serif;
font-weight: 700;
}
h2 {
font-family: 'Open Sans', sans-serif;
font-weight: 700;
}
article {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
}
b {
font-family: 'Open Sans', sans-serif;
font-weight: 700;
}
i {
font-family: 'Open Sans', sans-serif;
font-style: italic;
}
textarea {
width: 100%;
}
button {
cursor: pointer;
cursor: hand;
}
p.title {
margin: 0px 0px 3px 0px;
}
a.link {
color: #4284B0;
}
a.link:visited {
color: #9c4be7;
}
/* Pattern styles */
#css-table {
display: table;
width: 100%;
}
#col-1 {
display: table-cell;
width: 30%;
border: 1px solid #4284B0;
}
#col-2 {
display: table-cell;
width: 70%;
border-width: 1px 0px;
border-style: solid;
border-color: #4284B0;
}
textarea#syntax {
height: 10rem;
font-family: monospace;
}
textarea#input {
height: 4rem;
font-family: monospace;
}
.example {
display: table;
width: 100%;
}
.discuss {
display: table-cell;
width: 40%;
/*width: 25rem;
float: left;
*/
}
.result {
display: table-cell;
width: 60%;
}
button {
width: 5rem;
}
var exp, result, htmlResult;
var strings = {};
var $syntax, $input;
// set up for the matched pairs tab
var matchedPairs = function() {
$syntax.val(strings.grammar1);
$input.val(strings.input11);
htmlResult = $("#matched-here");
htmlResult.html("");
}
// set up for the unmatched pairs tab
var unmatchedPairs = function() {
$syntax.val(strings.grammar1);
$input.val(strings.input21);
htmlResult = $("#unmatched-here");
htmlResult.html("");
}
// set up for pairs within pairs tab
var insertedPairs = function() {
$syntax.val(strings.grammar1);
$input.val(strings.input31);
htmlResult = $("#internal-here");
htmlResult.html("");
}
// set for inserted text tab
var addedText = function() {
$syntax.val(strings.grammar4);
$input.val(strings.input4);
htmlResult = $("#text-here");
htmlResult.html("");
}
// set up for HTML tags tab
var htmlTags = function() {
$syntax.val(strings.grammar5);
$input.val(strings.input5);
htmlResult = $("#html-tags-here");
htmlResult.html("");
}
// the button-click functions
var execMB = function() {
$syntax.val(strings.grammar12);
$input.val(strings.input12);
exec();
}
var execMHC = function() {
$syntax.val(strings.grammar13);
$input.val(strings.input13);
exec();
}
var execAU = function() {
$syntax.val(strings.grammar31);
$input.val(strings.input33);
exec();
}
var execAM = function() {
$syntax.val(strings.grammar31);
$input.val(strings.input34);
exec();
}
var execLU = function() {
$input.val(strings.input22);
exec();
}
var execNP = function() {
$input.val(strings.input23);
exec();
}
var execI = function() {
$syntax.val(strings.grammar3);
$input.val(strings.input31);
exec();
}
var execIM = function() {
$syntax.val(strings.grammar3);
$input.val(strings.input32);
exec();
}
var execEI = function() {
$syntax.val(strings.grammar41);
$input.val(strings.input41);
exec();
}
var execQI = function() {
$syntax.val(strings.grammar42);
$input.val(strings.input42);
exec();
}
var execPM = function() {
$syntax.val(strings.grammar51);
$input.val(strings.input51);
exec();
}
var execPM2 = function() {
$syntax.val(strings.grammar51);
$input.val(strings.input52);
exec();
}
// execute the pattern match
var exec = function() {
try {
exp = new ApgExp($syntax.val());
result = exp.exec($input.val());
if (result) {
html = result.toHtml();
} else {
html = "<h3>result: null</h3>";
}
} catch (e) {
if (e.name === "ApgExpError") {
html = "<h3>ApgExpError</h3>";
html += e.toHtml();
} else if(e instanceof Error){
html = "<h3>Error</h3>";
html += e.message;
}else{
html = "<h3>unknown exception</h3>";
html += e;
}
}
htmlResult.html(html);
}
// handle the tab-click event
var tabSetup = function(event, ui) {
switch (ui.newPanel.selector) {
default:
case "#col-2-tab-1":
matchedPairs()
break;
case "#col-2-tab-2":
unmatchedPairs()
break;
case "#col-2-tab-3":
insertedPairs()
break;
case "#col-2-tab-4":
addedText()
break;
case "#col-2-tab-5":
htmlTags()
break;
}
}
$(document).ready(function() {
// SABNF syntax for simple matched parentheses
strings.grammar1 = "P = L P R / L R\n";
strings.grammar1 += 'L = "("\n';
strings.grammar1 += 'R = ")"\n';
// SABNF syntax for simple matched curly braces
strings.grammar12 = "P = L P R / L R\n";
strings.grammar12 += 'L = "{"\n';
strings.grammar12 += 'R = "}"\n';
// SABNF syntax for simple matched HTML comment tags
strings.grammar13 = "P = L P R / L R\n";
strings.grammar13 += 'L = "<!--"\n';
strings.grammar13 += 'R = "-->"\n';
// SABNF syntax for entire string matched parentheses
strings.grammar31 = "";
strings.grammar31 += "matched = %^ P %$\n";
strings.grammar31 += "P = L P R / L R\n";
strings.grammar31 += 'L = "("\n';
strings.grammar31 += 'R = ")"\n';
// SABNF syntax for internal pairs of matched parentheses
strings.grammar3 = "P = L 1*P R / L R\n";
strings.grammar3 += 'L = "("\n';
strings.grammar3 += 'R = ")"\n';
// SABNF syntax for internal pairs of matched parentheses
// with text inbetween
strings.grammar4 = "P = L text 1*(P text) R / L text R\n";
strings.grammar4 += 'L = "<"\n';
strings.grammar4 += 'R = ">"\n';
strings.grammar4 += 'text = *(%d32-59/ %d61 / %d63-126)\n';
// SABNF syntax for internal pairs of matched angle brackets
// with text inbetween & escaped brackets
strings.grammar41 = "P = L text 1*(P text) R / L text R\n";
strings.grammar41 += 'L = "<"\n';
strings.grammar41 += 'R = ">"\n';
strings.grammar41 += 'text = *(escaped / (%d32-59/ %d61 / %d63-126))\n';
strings.grammar41 += 'escaped = "\\<" / "\\>"\n';
// SABNF syntax for internal pairs of matched angle brackets
// with text inbetween & quoted strings with brackets
strings.grammar42 = "P = L text 1*(P text) R / L text R\n";
strings.grammar42 += 'L = "<"\n';
strings.grammar42 += 'R = ">"\n';
strings.grammar42 += 'text = *(quoted / (%d32-59/ %d61 / %d63-126))\n';
strings.grammar42 += 'quoted = %d34 qtext %d34\n';
strings.grammar42 += 'qtext = *(%d32-33 / %d35-126)\n';
// SABNF syntax for internal pairs of named HTML tags
// with text inbetween
strings.grammar5 = "P = L text 1*(P text) R / L text R\n";
strings.grammar5 += 'L = "<" name ">"\n';
strings.grammar5 += 'R = "</" name ">"\n';
strings.grammar5 += 'text = *(%d32-59 / %d61-126 / %d9-10 / %d13)\n';
strings.grammar5 += 'name = 1*(%d65-90 / %d97-122)\n';
// SABNF syntax for internal pairs of named HTML tags
// matching of opening and closing tags
strings.grammar51 = '';
strings.grammar51 += 'tags = %^ P %$\n';
strings.grammar51 += 'P = "<" name ">" text 1*(P text) "</" \\%pname ">"\n';
strings.grammar51 += ' / "<" name ">" text "</" \\%pname ">"\n';
strings.grammar51 += 'text = *(%d32-59 / %d61-126 / %d9-10 / %d13)\n';
strings.grammar51 += 'name = 1*(%d65-90 / %d97-122)\n';
// some sample input strings
strings.input11 = "()";
strings.input12 = "{{}}";
strings.input13 = "<!--<!---->-->";
strings.input21 = "(()";
strings.input22 = "(((())()))";
strings.input23 = "((";
strings.input31 = "(()())";
strings.input32 = "((()(())()()(((())))()()()))";
strings.input33 = "(()";
strings.input34 = "((()))";
strings.input4 = "<up 1<up 2< middle 1 >between<middle 2>down 2>down 1>";
strings.input41 = "<up 1<up \\<up 2< middle 1 >\\<between\\><middle 2>down down\\> 2>down 1>";
strings.input42 = '<up 1<"<ignore quoted"< middle 1 >between<middle 2>"ignore quoted>">down 1>';
strings.input5 = '<div>description <b>bold stuff</b>\n <div> inner text </span>\n</div>';
strings.input51 = '<div>description <b>bold stuff</b>\n <article> inner text </article>\n</div>';
strings.input52 = '<div>description <b>bold stuff</b>\n <article> inner text </span>\n</div>';
// jQuery values
$syntax = $("#syntax");
$input = $("#input");
// page setup
$("#col-1").tabs();
$("#col-2").tabs();
$("#exec").click(exec);
$("#matched-brackets").click(execMB);
$("#matched-html-comments").click(execMHC);
$("#long-unbalanced").click(execLU);
$("#no-pairs").click(execNP);
$("#anchors-unmatched").click(execAU);
$("#anchors-matched").click(execAM);
$("#internal").click(execI);
$("#internal-more").click(execIM);
$("#escape-it").click(execEI);
$("#quote-it").click(execQI);
$("#parent-mode").click(execPM);
$("#parent-mode2").click(execPM2);
$("#col-2").on("tabsactivate", tabSetup);
matchedPairs();
});
Also see: Tab Triggers