title: Callback function "is not defined"
body: <p>I am building a script that fetches multiple JSON feeds from Tumblr and creates HTML lists based on that data. Pretty straightforward concept.</p>
  
  <p>Here's the output: <a href="http://fotis.co/tumblr/index.html" rel="nofollow">http://fotis.co/tumblr/index.html</a></p>
  
  <p>The script is partly working as I'm stumbling on "callback function not defined" issues. That happens only when I choose to use a callback function when requesting the Tumblr JSON feed. By default, if you don't specify a callback function via the Tumblr API, the JSON object returned is assigned to a variable named tumblr_api_read. So the JSON actually returns:</p>
  
  <pre><code>var tumblr_api_read = {the JSON object data goes here};
  </code></pre>
  
  <p>If I use a callback function, the JSON data is returned like this (as expected):</p>
  
  <pre><code>callbackFunctionName({the JSON object data goes here});
  </code></pre>
  
  <p>If you check out the script code here <a href="http://fotis.co/tumblr/tumblr.js" rel="nofollow">http://fotis.co/tumblr/tumblr.js</a>:</p>
  
  <pre><code>/* Read Tumblr */
  
  function ready(cb) {
      /in/.test(document.readyState) ? setTimeout('ready('+cb+')', 9) : cb();
  }
  
  function getTumblrFeed(params) {
      /*
      Legend:
      start - The post offset to start from. The default is 0.
      num - The number of posts to return. The default is 20, and the maximum is 50.
      type - The type of posts to return. If unspecified or empty, all types of posts are returned. Must be one of text, quote, photo, link, chat, video, or audio.
      id - A specific post ID to return. Use instead of start, num, or type.
      filter - Alternate filter to run on the text content. Allowed values:
          text - Plain text only. No HTML.
          none - No post-processing. Output exactly what the author entered. (Note: Some authors write in Markdown, which will not be converted to HTML when this option is used.)
      tagged - Return posts with this tag in reverse-chronological order (newest first). Optionally specify chrono=1 to sort in chronological order (oldest first).
      search - Search for posts with this query.
      */
      if(params.blogurl) var blogurl = params.blogurl;
      if(params.postcount) var num = params.postcount;
      var jsonurl = document.location.protocol+ '//' +blogurl+ '/api/read/json?num=' +num;
      if(params.type) jsonurl += '&amp;type=' + params.type;
      if(params.tagged) jsonurl += '&amp;tagged=' + params.tagged;
      if(params.search) jsonurl += '&amp;search=' + params.search;
      if(params.callback) jsonurl += '&amp;callback=' + params.callback;
      var jsonfeedscript = document.createElement('script');
      jsonfeedscript.setAttribute('charset', 'utf-8');
      jsonfeedscript.setAttribute('type', 'text/javascript');
      jsonfeedscript.setAttribute('async', 'true');
      jsonfeedscript.setAttribute('src', jsonurl);
      return jsonfeedscript;
  }
  
  function renderResults(settings) {
      var tumblrObj = (settings.callback) ? settings.callback : tumblr_api_read;
  
      var i = 0;
      var c = document.getElementById(settings.container);
  
      for(i; i&lt;tumblrObj.posts.length; i++){
          // URL
          var postUrl = tumblrObj.posts[i]['url-with-slug'];
          // Title
          if(tumblrObj.posts[i]['regular-title']){
              var postTitle = tumblrObj.posts[i]['regular-title'];
          } else if(tumblrObj.posts[i]['quote-text']){
              var postTitle = tumblrObj.posts[i]['quote-text'];
          } else if(tumblrObj.posts[i]['link-text']){
              var postTitle = tumblrObj.posts[i]['link-text'];
          } else if(tumblrObj.posts[i]['audio-caption']){
              var postTitle = tumblrObj.posts[i]['audio-caption'];
          } else if(tumblrObj.posts[i]['photo-caption']){
              var postTitle = tumblrObj.posts[i]['photo-caption'];
          } else if(tumblrObj.posts[i]['video-caption']){
              var postTitle = tumblrObj.posts[i]['video-caption'];
          } else if(tumblrObj.posts[i]['conversation-text']){
              var postTitle = tumblrObj.posts[i]['conversation-text'];
          } else {
              var postTitle = '';
          }
          // Date
          var postDate = tumblrObj.posts[i]['date']; // or: date-gmt, unix-timestamp
          // Type
          var postType = tumblrObj.posts[i]['type'];
          // Output
          var output = settings.theme.replace("{postUrl}",postUrl).replace("{postTitle}",postTitle).replace("{postDate}",postDate);
          c.innerHTML += output;
      }
  
      // Hide the loader
      var l = document.getElementById(settings.loader);
      c.removeChild(l);
  }
  
  function readTumblr(settings) {
      // Load JSON data
      var head = document.getElementsByTagName('head')[0];
      var jsonfeedscript = getTumblrFeed(settings);
      head.appendChild(jsonfeedscript);
  
      jsonfeedscript.onload = function(){
          renderResults(settings);
      }
  }
  </code></pre>
  
  <p>You will see that I do a check if the JSON feed is invoked with a callback function (inside readTumblr()), otherwise I just use the default object "tumblr_api_read". If no callback function is defined where the script is initialized (inside index.html) the Tumblr JSON data are properly rendered (see Containers 2 and 3 in the html output). If I DO define a callback function, I get something like "callbackFunctioName is not defined" and then rendering fails.</p>
  
  <p>Am I missing something here? Is it a scope issue? And if so, how can I bypass it?</p>
  
  <p>Thanks in advance for any answers.</p>
  
  <p><strong>EDIT 1</strong>: Updated script code above.</p>