cssAudio - Activefile-genericCSS - ActiveGeneric - ActiveHTML - ActiveImage - ActiveJS - ActiveSVG - ActiveText - Activefile-genericVideo - Activehtmlicon-personicon-teamoctocatpop-outspinnerstartv

Pen Settings

CSS Base

Vendor Prefixing

Add External CSS

These stylesheets will be added in this order and before the code you write in the CSS editor. You can also add another Pen here, and it will pull the CSS from it. Try typing "font" or "ribbon" below.

Quick-add: + add another resource

Add External JavaScript

These scripts will run in this order and before the code in the JavaScript editor. You can also link to another Pen here, and it will run the JavaScript from it. Also try typing the name of any popular library.

Quick-add: + add another resource

Code Indentation

     

Save Automatically?

If active, Pens will autosave every 30 seconds after being saved once.

Auto-Updating Preview

If enabled, the preview panel updates automatically as you code. If disabled, use the "Run" button to update.

            
               <div id="css-table">
  <div id="col-1">
  <ul>
    <li><a href="#col-1-tab-1">Example 7</a></li>
  </ul>
  <div id="col-1-tab-1">
  <article>
   <h1>select matching brackets</h1>
   <p>
    <b>text to search:</b><br>
    <textarea class="input" id="cursor-area">
var brackets = function() {
  for(var i = 0; i < 10; i += 1){
    if(i === 1){
      console.log("two opening brackets, {, here");
    }else if(i = 2){
      console.log("only one closing bracket, }, so far");
      if(true){
        console.log("now we are three deep in opening brackets, {, so far");
        if(true){
          console.log("lots of { and } to deal with here");
        }
      }
    }
  }
}</textarea>
   </p>
   <p>
   <b>Problem:</b> When the mouse clicks on a bracket, <code>{</code> or <code>}</code>,
   highlight its matching bracket by selecting all text in the phrase
   including the opening and closing brackets. Brackets in quoted strings are to be ignored.
   </p>
   <p>
   <b>Solution:</b> The working functions are <code>findOpening()</code> and <code>findClosing()</code>
   which respectively find the opening or closing member of a matched pair of brackets.
   </p>
   <b>Pattern Syntax:</b> The ABNF pattern syntax for matching nested pairs of brackets is:
   <pre id="pattern"></pre> 
   </p>
   <p>
   <b>Notes: </b> Working with textareas is notoriously browser-dependent.
   Here I'm do a minimum of cursor management in 
   the functions <code>getCursorPos()</code> and <code>setSelection()</code>.
   They have been tested on Chrome 49, Firefox 44 and IE 11.
   My apologies if they don't work in your browser.
   (On the other hand, you are more than welcome to jump over to the JS panel and fix them. :) )
   </p>
   <p>
   </p>
   <div class="discussion">
   </div>
  </article>
  </div>
  </div>
  <div id="col-2">
  <ul>
    <li><a href="#col-2-tab-1">message</a></li>
  </ul>
  <div id="col-2-tab-1">
  <article>
   <div id="apgexp-result"></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;
}

textarea.input {
  font-size: .9rem;
  font-family: monospace;
}

/* Pattern styles */
#css-table {
  display: table;
  width: 100%
}

#col-1 {
  display: table-cell;
  width: 40%;
  border: 1px solid #4284B0;
}

#col-2 {
  display: table-cell;
  width: 60%;
  border-width: 1px 0px;
  border-style: solid;
  border-color: #4284B0;
}

button {
  font-size: 1em;
  font-weight: bold;
  cursor: pointer;
  cursor: hand;
  margin: 0px 0px 2px 0px;
}

button.tryit-button {
  width: 10rem;
}


#apgexp-def, #input-data {
  width: 95%;
  font-size: .9rem;
  font-family: monospace;
}

#cursor-area {
  height: 20em;
}

span.error{
	color: red;
}

            
          
!
            
              var exp, expSQuote, expDQuote, result, msg;
var $e, $area, $msg;

// given the position of the opening bracket
// find the position of the closing bracket
var findClosing = function(pos) {
  msg = "";
  msg += "<h2>Match From Opening Bracket Forward To Closing Pair</h2>"

  // anchor the search at the position of the opening bracket
  exp.lastIndex = pos;
  result = exp.exec($e.value);
  if(result){
    
    // find the index of the closing bracket (end of phrase) 
    var end = pos + result.rules.P[0].phrase.length;
    setSelection(pos, end);
    
    // display a success message
    msg += "opening bracket at index: " + pos;
    msg += "<br>closing bracket at index: "+ (end-1);
  }else{
    
    // display an error message
    msg += '<span class="error">no matching closing bracket found</span>';
  }
  $msg.html(msg);
}

//given the position of the closing bracket
//find the position of the opening bracket
var findOpening = function(pos) {
  msg = "";
  msg += "<h2>Match From Closing Bracket Back To Opening Pair</h2>"
  var found = false;
  
  // search from beginning of string for **correct** opening bracket
  for(var i = 0; i < pos; i += 1){
    var char = $e.value.charCodeAt(i);
    if(char === 34){
      // skip over double-quoted strings
      expDQuote.lastIndex = i;
      result = expDQuote.exec($e.value);
      if(result){
        i += result.length -1;
      }
    }else if(char === 39){
      // skip over single-quoted strings
      expSQuote.lastIndex = i;
      result = expSQuote.exec($e.value);
      if(result){
        i += result.length -1;
      }
    }else if(char === 123){
      
      // found opening bracket, anchor the search to its index
      exp.lastIndex = i;
      result = exp.exec($e.value);
      if(result){
        
        // found a bracket pair
        // test closing bracket of this pair against the closing bracket we started with
        var beg = result.rules.P[0].index;
        var end = result.rules.P[0].index + result.rules.P[0].phrase.length;
        if(end === (pos + 1)){
          
          // found it
          setSelection(beg, end);
          found = true;
          
          // display a success message
          msg += "opening bracket at index: " + beg;
          msg += "<br>closing bracket at index: "+ pos;
          break;
        }
      }
    }
  }
  if(!found){
    
    // display an error message
    msg += '<span class="error">no matching opening bracket found</span>';
  }
  $msg.html(msg);
}

// return the cursor position after a mouse click
var getCursorPos = function(){
  var pos = -1;
  if ($e.selectionStart !== undefined) {
    pos = $e.selectionStart;
  }else{
    msg = "<h2>No Browser Support For Cursor Management</h2>";
    msg += "<b>browser:</b> ";
    if(navigator && navigator.appCodeName){
      msg += navigator.appCodeName;
      if(navigator.appName){
        msg += ": " + navigator.appName;
      }
      if(navigator.appVersion){
        msg += ": " + navigator.appVersion;
      }
    }else{
      msg += "unknown";
    }
    $msg.html(msg);
  }
  return pos;
}

// set the selection
var setSelection = function(beg, end){
  if ($e.selectionStart !== undefined) {
    $e.selectionStart = beg;
    $e.selectionEnd = end;
  }
}

// mouse up event
// the cursor has now been set to the mouse click position
var mouseUp = function(event) {
  var pos = getCursorPos();
  if(pos >= 0){
    var char = $e.value.charCodeAt(pos);
    if(char === 123){
      
      // cursor is on an opening bracket, {: find the matching }
      findClosing(pos);
    }else if(char === 125){
      
      // cursor is on an closing bracket, }: find the matching {
      findOpening(pos);
    }else{
      
      // cursor not on a bracket: just display the cursor location
      msg = "";
      msg += "<h2>Cursor Not On Bracket</h2>";
      msg += "cursor at index: " + pos;
      $msg.html(msg);
    }
  }
}

// mouse down event
// clear any selection before the cursor position is set
var mouseDown = function(event) {
  setSelection($e, 0, 0);
}
$(document).ready(function() {
  
  // the ABNF pattern syntax for matching nested, pairs of brackets with text between
  var pairs = "";
  pairs += "P     = L text 1*(P text) R              ; the nested pairs with text between\n";
  pairs += "      / L text R                         ; the middle pair\n";
  pairs += 'L     = "{"                              ; the left, opening bracket\n';
  pairs += 'R     = "}"                              ; the right, closing bracket\n';
  pairs += 'text  = *(squote                         ; single-quoted text\n';
  pairs += '       / dquote                          ; double-quoted text\n';
  pairs += '       / %d32-122 / %d124 / %d126        ; all ASCII characters except { and }\n';
  pairs += '       / %d9-10 / %d13)                  ; including tabs and line breaks\n';
  pairs += 'squote = %d39 *(%d32-38 / %d40-126) %d39 ; single-quoted text\n';
  pairs += 'dquote = %d34 *(%d32-33 / %d35-126) %d34 ; double-quoted text\n';
  
  // set the "sticky" flag to anchor the search at exp.lastIndex
  exp = new ApgExp(pairs, "y");
  
  // quoted string objects
  expSQuote = new ApgExp("squote = %d39 *(%d32-38 / %d40-126) %d39\n", "y");
  expDQuote = new ApgExp('dquote = %d34 *(%d32-33 / %d35-126) %d34\n', "y");
  
  // jQuery values
  $msg = $("#apgexp-result");
  $area = $("#cursor-area");
  $e = $area[0]

  // page set up
  $area.mouseup(mouseUp);
  $area.mousedown(mouseDown);
  $("#col-1").tabs();
  $("#col-2").tabs();
  $("#pattern").html(pairs);
  $msg.html('<i>click the cursor in the text area</i>');
});

            
          
!
999px
Close

Asset uploading is a PRO feature.

As a PRO member, you can drag-and-drop upload files here to use as resources. Images, Libraries, JSON data... anything you want. You can even edit them anytime, like any other code on CodePen.

Go PRO

Loading ..................

Console