Need a js guru to help me out with this

  • mindfullsilence
  • Professor
  • Professor
  • User avatar
  • Posts: 854

Post 3+ Months Ago

So I've decided I suck at javascript. So I'm working on a personal project to get better. I'm trying to create a script that will autoclose an html element that has been typed into a textarea. I've gotten so close and then I hit a brick wall. You can check out the example here: demo.

What is supposed to happen is the script runs every time someone hits the backslash("/"). After the event is triggered, it should append whatever the last open element is.
I'm loading my text into the function up to wherever the cursor is. Then finding all the html elements and sticking them into an array that is pushed into another function. The second function matches each element up in pairs and spits out the remainder(the unclosed tag).
You can see the script here: script

My issue is that if I embed a couple elements and start closing them, I end up with something like "<///p>" instead of "</p>".
Any ideas?
  • SpooF
  • ٩๏̯͡๏۶
  • Bronze Member
  • User avatar
  • Posts: 3422
  • Loc: Richland, WA

Post 3+ Months Ago

I through this together. I think it works.

JAVASCRIPT Code: [ Select ]
function priorElement(html,cursor_pos){
 
    var re = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/gi
    var matches = html.match(re,html)
 
    var elements = [];
    var positions = [];
 
    // Run through all the matches
    for ( x in matches )
    {
        // Strip all the randon stuff so we just have the element.
        var stripped_element = matches[x].replace(/\s[^\/>]+/g,'');
 
        // If it has a trailing backslash ignore it
        if(stripped_element.match(/\w\//)) // may want to look for these instead like in your script area|base|basefont|br|hr|input|img|link|meta
            continue;
 
        // Get rid of the `>` so we can match Ex. <a href="" class=""> turns, we need to
        // matchs `<a` and not `<a>`    
        var stripped_element = stripped_element.substring(0,stripped_element.length-1)
 
        positions.push(html.search(stripped_element));
        elements.push(stripped_element);
 
    }
 
    if(positions && elements) {
       
        var element = 0;
        for(var i in positions)
        {
            if(positions[i] > cursor_pos)
            {
                // Find the element right before our cursor
                element = i - 1;
                break;
            }
        }
 
        if(elements[element] == undefined)
            return;
 
        // return just the element, a, center, div, span...
        return elements[element].replace(/[\<\/\>]/,'');
    }
    return;
}
  1. function priorElement(html,cursor_pos){
  2.  
  3.     var re = /<\/?\w+((\s+\w+(\s*=\s*(?:".*?"|'.*?'|[^'">\s]+))?)+\s*|\s*)\/?>/gi
  4.     var matches = html.match(re,html)
  5.  
  6.     var elements = [];
  7.     var positions = [];
  8.  
  9.     // Run through all the matches
  10.     for ( x in matches )
  11.     {
  12.         // Strip all the randon stuff so we just have the element.
  13.         var stripped_element = matches[x].replace(/\s[^\/>]+/g,'');
  14.  
  15.         // If it has a trailing backslash ignore it
  16.         if(stripped_element.match(/\w\//)) // may want to look for these instead like in your script area|base|basefont|br|hr|input|img|link|meta
  17.             continue;
  18.  
  19.         // Get rid of the `>` so we can match Ex. <a href="" class=""> turns, we need to
  20.         // matchs `<a` and not `<a>`    
  21.         var stripped_element = stripped_element.substring(0,stripped_element.length-1)
  22.  
  23.         positions.push(html.search(stripped_element));
  24.         elements.push(stripped_element);
  25.  
  26.     }
  27.  
  28.     if(positions && elements) {
  29.        
  30.         var element = 0;
  31.         for(var i in positions)
  32.         {
  33.             if(positions[i] > cursor_pos)
  34.             {
  35.                 // Find the element right before our cursor
  36.                 element = i - 1;
  37.                 break;
  38.             }
  39.         }
  40.  
  41.         if(elements[element] == undefined)
  42.             return;
  43.  
  44.         // return just the element, a, center, div, span...
  45.         return elements[element].replace(/[\<\/\>]/,'');
  46.     }
  47.     return;
  48. }
  • mindfullsilence
  • Professor
  • Professor
  • User avatar
  • Posts: 854

Post 3+ Months Ago

I wanted the elements to be closed in succession. So that if I have embedded elements, the function will close them in order. Example:
HTML Code: [ Select ]
<div>
<p>
<a>
 
  1. <div>
  2. <p>
  3. <a>
  4.  

If I were to type "</" the result would be:
  • First time: a
  • Second time: p
  • Third time: div

I've adapted your code, spoof, and almost have it working. The only issue is that with embedded elements such as illustrated above, the result is as follow:
  • First time: a
  • Second time: a
  • Third time: p
  • Fourth time: div
Any ideas? demo
  • mindfullsilence
  • Professor
  • Professor
  • User avatar
  • Posts: 854

Post 3+ Months Ago

I've made some changes to my code that follow a better logic but am still stuck with pretty much the same problem.

Here's the code I have so far:
JAVASCRIPT Code: [ Select ]
function unclosed(html,cursor_pos){
 
   //Remove any text after the cursor
   html = html.substr(0,cursor_pos);
   var re = /<[^<]+?>/gi
   var matches = html.match(re,html)
   var openers = [];
   var closers = [];
   var unclosed = [];
   
   // Run through all the matches
   for ( x in matches )
   {
      // Strip all the random stuff so we just have the element.
      var stripped_element = matches[x].replace(/\s[^\/>]+/g,'');
     
      // If it has a trailing backslash ignore it, since it's slef-closing
      if(stripped_element.match(/\w\//))
         continue;
 
      // Get rid of the `>` so we can match, we need to match `<a` and not `<a>`  
      var stripped_element = stripped_element.substring(0,stripped_element.length-1);
      stripped_element = stripped_element.replace("<","");
     
      // now we check to see if it is a closing element or not
      if(stripped_element.match(/\//))
      {
         //if it is, stick it in the "closers" array
         closers.push(stripped_element);
      }
      else
      {
         //otherwise put it in the "openers" array
            openers.push(stripped_element);
      }
   }
   
   // if there are just as many closing tags as there are opening tags
   // than all tags are closed, so return false.
   if(openers.length == closers.length || openers.length == 0)
   {
      return false;
   }
   
   // if the closers array is empty, push the openers to the
   // "unclosed" array and return the last entry
   else if(closers.length == 0 && openers.length > 0) {
      for ( x in openers )
      {
         unclosed.push(openers[x]);
      }
      return unclosed.pop();
   }
   
   // now we check for matches between opening and closing tags.
   else
   {
      // go through each entry in the "openers" array
      for (x in openers)
      {
         hasClose = new RegExp("\/"+openers[x],"gi");
         
         // see if theres a match for it in the "closers" array
         for (i in closers)
         {
            // if there is, remove the match from both arrays
            // and constinue to the next entry.
            if(closers[i].match(hasClose))
            {
               closers.splice(i,1);
               openers.splice(x,1);
               break;
            }
           
            // if there's not, add the "openers" entry to the
            // "unclosed" array
            else
            {
               unclosed.push(openers[x]);
            }
         }
      }
   // now return the last entry in the "unclosed" array.
   return unclosed.pop();
   } 
}
 
  1. function unclosed(html,cursor_pos){
  2.  
  3.    //Remove any text after the cursor
  4.    html = html.substr(0,cursor_pos);
  5.    var re = /<[^<]+?>/gi
  6.    var matches = html.match(re,html)
  7.    var openers = [];
  8.    var closers = [];
  9.    var unclosed = [];
  10.    
  11.    // Run through all the matches
  12.    for ( x in matches )
  13.    {
  14.       // Strip all the random stuff so we just have the element.
  15.       var stripped_element = matches[x].replace(/\s[^\/>]+/g,'');
  16.      
  17.       // If it has a trailing backslash ignore it, since it's slef-closing
  18.       if(stripped_element.match(/\w\//))
  19.          continue;
  20.  
  21.       // Get rid of the `>` so we can match, we need to match `<a` and not `<a>`  
  22.       var stripped_element = stripped_element.substring(0,stripped_element.length-1);
  23.       stripped_element = stripped_element.replace("<","");
  24.      
  25.       // now we check to see if it is a closing element or not
  26.       if(stripped_element.match(/\//))
  27.       {
  28.          //if it is, stick it in the "closers" array
  29.          closers.push(stripped_element);
  30.       }
  31.       else
  32.       {
  33.          //otherwise put it in the "openers" array
  34.             openers.push(stripped_element);
  35.       }
  36.    }
  37.    
  38.    // if there are just as many closing tags as there are opening tags
  39.    // than all tags are closed, so return false.
  40.    if(openers.length == closers.length || openers.length == 0)
  41.    {
  42.       return false;
  43.    }
  44.    
  45.    // if the closers array is empty, push the openers to the
  46.    // "unclosed" array and return the last entry
  47.    else if(closers.length == 0 && openers.length > 0) {
  48.       for ( x in openers )
  49.       {
  50.          unclosed.push(openers[x]);
  51.       }
  52.       return unclosed.pop();
  53.    }
  54.    
  55.    // now we check for matches between opening and closing tags.
  56.    else
  57.    {
  58.       // go through each entry in the "openers" array
  59.       for (x in openers)
  60.       {
  61.          hasClose = new RegExp("\/"+openers[x],"gi");
  62.          
  63.          // see if theres a match for it in the "closers" array
  64.          for (i in closers)
  65.          {
  66.             // if there is, remove the match from both arrays
  67.             // and constinue to the next entry.
  68.             if(closers[i].match(hasClose))
  69.             {
  70.                closers.splice(i,1);
  71.                openers.splice(x,1);
  72.                break;
  73.             }
  74.            
  75.             // if there's not, add the "openers" entry to the
  76.             // "unclosed" array
  77.             else
  78.             {
  79.                unclosed.push(openers[x]);
  80.             }
  81.          }
  82.       }
  83.    // now return the last entry in the "unclosed" array.
  84.    return unclosed.pop();
  85.    } 
  86. }
  87.  


The problem is on the third embedded html tag. Instead of this result:
HTML Code: [ Select ]
<div><p><a>
</a></p></div>
 
  1. <div><p><a>
  2. </a></p></div>
  3.  

I'm getting this:
HTML Code: [ Select ]
<div><p><a>
</a></p></p>
 
  1. <div><p><a>
  2. </a></p></p>
  3.  

Post Information

  • Total Posts in this topic: 4 posts
  • Users browsing this forum: No registered users and 28 guests
  • You cannot post new topics in this forum
  • You cannot reply to topics in this forum
  • You cannot edit your posts in this forum
  • You cannot delete your posts in this forum
  • You cannot post attachments in this forum
 
cron
 

© 1998-2014. Ozzu® is a registered trademark of Unmelted, LLC.