title: Moving inline javascript function to external file and convert to jQuery
body: <p>I am trying to optimize my "spoiler" bbcode on phpBB3.</p>
  
  <p>Right now, I have a working solution, but the inline javascript is injected by phpBB every time the "spoiler" bbcode tag is used. I want to call a common function instead of adding it inline every time the bbcode is used.</p>
  
  <p>Here is that working inline javascript:</p>
  
  <pre><code>&lt;div class="spoiler"&gt;
      &lt;div class="spoiler-title"&gt;
          &lt;span onclick="if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = ''; this.parentNode.getElementsByTagName('a')[0].innerText = 'hide'; } else { this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none'; this.parentNode.getElementsByTagName('a')[0].innerText = 'show'; }"&gt;
              &lt;strong&gt;{TEXT1}&lt;/strong&gt; (&lt;a href="#" class="spoiler-btn" title="Show hidden content"&gt;show&lt;/a&gt;)
          &lt;/span&gt;
      &lt;/div&gt;
      &lt;div class="spoiler-text"&gt;
          &lt;div style="display: none;"&gt;
              {TEXT2}
          &lt;/div&gt;
      &lt;/div&gt;
  &lt;/div&gt;
  </code></pre>
  
  <p>For ease of reading, the inline onclick function is repeated here:</p>
  
  <pre><code>if (this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display != '') {
      this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = '';
      this.parentNode.getElementsByTagName('a')[0].innerText = 'hide';
  } else {
      this.parentNode.parentNode.getElementsByTagName('div')[1].getElementsByTagName('div')[0].style.display = 'none';
      this.parentNode.getElementsByTagName('a')[0].innerText = 'show';
  }
  </code></pre>
  
  <p>Clicking the anchor with the class of "spoiler-btn" has a preventDefaults on it, to prevent the click from taking you to the top of the page:</p>
  
  <pre><code>$(document).ready(function(){
  
      $(".spoiler-btn").click(
        function(e) {
          e.preventDefault();
        }
      );
  
  });
  </code></pre>
  
  <p>I was trying to replace the span onclick inline javascript with a function call that passes 'this' to an external javascript file. I couldn't seem to get that working, so I tried using jQuery to capture 'this' to traverse up the DOM to find the "div" contained within the "spoiler-text" div and manipulate the display:none. There can be multiple of these spoiler tags on the page, so I cannot give the div inside of the "spoiler-text" div an id. </p>
  
  <p>Here I changed the onclick of the span to the external function:</p>
  
  <pre><code>onclick="spoilerToggle(this);"
  </code></pre>
  
  <p>I then have the following in my external file:</p>
  
  <pre><code>var spoilerToggle = function(param) {
      if ($(this).parent('div').parent('div').hasClass('spoiler-text').css('style') == 'none') {
          ($(this).parent('div').parent('div').hasClass('spoiler-text').removeAttr('style'));
          ($(this).parent('div').$('a').text('hide'));
      } else {
          ($(this).parent('div').parent('div').hasClass('spoiler-text').css('display', 'none'));
          ($(this).parent('div').$('a').text('show'));
      }
  }
  </code></pre>
  
  <p>The console then gives the following error:
  bbcode.js:22 Uncaught TypeError: $(...).parent(...).parent(...).hasClass(...).css is not a function</p>
  
  <p>Line 22 is the line with the "if" check.</p>
  
  <p>jQuery is loaded on the site, and I've made sure to call my external javascript file right before the close of the body tag.</p>
  
  <p>I feel like I've gone down the rabbit hole and cannot see the light. I'm sure this is much easier than I am making it out to be.</p>
  
  <p>Any help is greatly appreciated. Thank you!</p>