title: Chrome Extension: popup.html dynamically create via contentscript.js
body: <p>I've read Google's Message passing page and I've also read similar questions here on StackOverflow.</p>
  
  <p>The full source for what I am working on is available on <a href="http://code.google.com/p/calendar-event-adder/source/browse/?r=3e6d040fa578ec49f1061e7cc092612f5b33f062" rel="nofollow">google code</a>.</p>
  
  <p>I right now have the contentscript.js insert links next to dates on a webpage that directs the user to Google's calendar event creation page with the date/time already filled out.</p>
  
  <p>contentscript.js</p>
  
  <pre><code>    /*
   * Copyright (c) 2010 Thomas Wolfe. All rights reserved.  Use of this
   * source code is governed by a Simplified BSD license that can be found in the
   * LICENSE file.
   */
  /*
   * Regex Matches
   * 12/31/2002     | Dec 31, 2002 | December 31 2002 | 12-31-2002 | 2002/12/31 (ISO 8601) | 12/31/2002 20:00 | 12/31/2002 08:00 PM
   * Non-Matches
   * 12/31/02  | 15/12/2002 (day month year) | 2002/12/3 (needs a two digit day in this case to prevent breaking 2 digit day)
   */
  var regex = /(((([0]?[1-9]|1[0-2])|(Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December))(\/|-|\.| |, )([0-2]?[0-9]|3[0-1])(\/|-|\.| |, )([1-2]\d{3}))|(([1-2]\d{3})(\/|-|\.| |, )(([0]?[1-9]|1[0-2])|(Jan|January|Feb|February|Mar|March|Apr|April|May|Jun|June|Jul|July|Aug|August|Sep|September|Oct|October|Nov|November|Dec|December))(\/|-|\.| |, )([0-2]?[0-9]|3[0-1]){2}))( (([0-1]?\d)|(2[0-3])):[0-5]\d)?( AM| am| PM| pm)?/ig;
  // Removes duplicate values from an array
  function unique(inputArray){
      var outputArray = new Array();
      o: for (var i = 0; i &lt; inputArray.length; i++) {
          for (var x = 0; x &lt; outputArray.length; x++) {
              if (outputArray[x] == inputArray[i]) 
                  continue o;
          }
          outputArray[outputArray.length] = inputArray[i];
      }
      return outputArray;
  }
  
  // Converts the given time into UTC, returns this in a string
  function getUTCDateString(y, m, d, h, min){
      var timeObj = new Date(y, m - 1, d, h, min);
      var dateStr = "" + timeObj.getUTCFullYear();
      dateStr += stringPad(timeObj.getUTCMonth() + 1);
      dateStr += stringPad(timeObj.getUTCDate());
      dateStr += "T" + stringPad(timeObj.getUTCHours());
      dateStr += stringPad(timeObj.getUTCMinutes()) + "00Z";
      return dateStr;
  }
  
  // Add a leading '0' if string is only 1 char
  function stringPad(str){
      var newStr = "" + str;
      if (newStr.length == 1) {
          newStr = "0" + newStr;
      }
      return newStr;
  }
  
  function getMonthByName(str){
      var newStr = "" + str;
      var month;
      switch (newStr) {
          case "Jan":
          case "January":
              month = 1;
              break;
          case "Feb":
          case "February":
              month = 2;
              break;
          case "Mar":
          case "March":
              month = 3;
              break;
          case "Apr":
          case "April":
              month = 4;
              break;
          case "May":
              month = 5;
              break;
          case "Jun":
          case "June":
              month = 6;
              break;
          case "Jul":
          case "July":
              month = 7;
              break;
          case "Aug":
          case "August":
              month = 8;
              break;
          case "Sep":
          case "September":
              month = 9;
              break;
          case "Oct":
          case "October":
              month = 10;
              break;
          case "Nov":
          case "November":
              month = 11;
              break;
          default:
              month = 12;
      }
      return month;
  }
  
  function indiciesOfText(stringToSearch, searchFor)
  {
   var regex = new RegExp(searchFor,"g"), result, indices = [];
   while ( (result = regex.exec(stringToSearch)) ) {
       indices.push(result.index+searchFor.length);
   }
   return indices;
  }
  function createLinkImg(dateStr)
  {
   var dateImg = document.createElement("IMG");
   dateImg.title = "Add this event to your Google Calendar";
   dateImg.src = chrome.extension.getURL("Config-date-16.png")
   var dateLink = document.createElement("A");
   dateLink.target = "_blank";
   dateLink.href = "http://www.google.com/calendar/event?action=TEMPLATE&amp;text=someevent&amp;dates=" + dateStr + "&amp;details=&amp;location=&amp;trp=false&amp;sprop=&amp;sprop=";
   dateLink.appendChild(dateImg);
   return dateLink;
  }
  function replaceText(dateStr, dateTxt, tobeReplacedNode) {
   dateLink = createLinkImg(dateStr);
   // if textNode search and replace
   if (tobeReplacedNode.nodeType == 3) {
    if (tobeReplacedNode.textContent.search(new RegExp(dateTxt,"g")) != -1) {
     var splitTxtNode = indiciesOfText(tobeReplacedNode.textContent,dateTxt);
     for (var k = 0; k &lt; splitTxtNode.length; k++) {
      if (k == 0) {
       var txtAfterOffsetNode = tobeReplacedNode.splitText(splitTxtNode[k]);
       tobeReplacedNode.parentNode.insertBefore(dateLink, tobeReplacedNode.nextSibling);
      }
      else {
       var txtAfterOffsetNode = txtAfterOffsetNode.splitText(splitTxtNode[k]-splitTxtNode[k-1]);
       txtAfterOffsetNode.parentNode.insertBefore(dateLink, txtAfterOffsetNode.nextSibling);
      }
     }
    }
   }
   if (tobeReplacedNode.hasChildNodes() &amp;&amp; splitTxtNode == null) {
    //recall this function
    for (var j = 0; j &lt; tobeReplacedNode.childNodes.length; j++) {
     replaceText(dateStr, dateTxt, tobeReplacedNode.childNodes[j]);
    }
   }
   //return tobeReplacedNode;
  }
  function getMonthDayYearHourMin(date) {
   var arraySplits = date.split(/(\/|-|\.| |, |:)/gi);
  
   // set time (hour/min)
   if (arraySplits.length &gt; 5) {
    hour = arraySplits[6];
    min = arraySplits[8];
    if (arraySplits.length &gt; 9) {
     ampm = arraySplits[10];
     if (ampm == "pm" | "PM") {
      hour = 12 + parseInt(hour);
      hour = hour.toString();
     }
    }
   }
   else // no time provided, set to 00:00
   {
    hour = "00";
    min = "00";
   }
   // if the year is not the first element day/year/month are in different locations
   if (arraySplits[0].length != 4 | (arraySplits[0] == "June" | "July")) {
    year = arraySplits[4];
  
    if (parseInt(arraySplits[0]) &gt; 12) {
     if (arraySplits[2].length &lt; 3) {
      month = arraySplits[2];
     }
     else {
      month = getMonthByName(arraySplits[2]);
     }
     day = arraySplits[0];
    }
    if (arraySplits[0].length &lt; 3) {
     month = arraySplits[0];
    }
    else {
     month = getMonthByName(arraySplits[0]);
    }
    day = arraySplits[2];
   }
   else {
    year = arraySplits[0];
    if (parseInt(arraySplits[2]) &gt; 12) {
     day = arraySplits[2];
     month = arraySplits[4];
    }
    else {
     month = arraySplits[2];
     day = arraySplits[4];
    }
   }
   return getUTCDateString(year, month, day, hour, min);
  }
  function replaceBody(date, bodyElement) {
   initDateString = getMonthDayYearHourMin(date);
      dateString = initDateString + "/" + initDateString;
  
   replaceText(dateString, date, bodyElement);
   return dateString;
  }
  
  // Test the text of the body element against our regular expression.
  if (regex.test(document.body.innerText)) {
      var bodyElement = document.getElementsByTagName("BODY")[0];
      var nonUniqueArrayDates = document.body.innerText.match(regex); // array of date/time values
      var arrayDates = unique(nonUniqueArrayDates);
   var arrayDateStr = new Array();
  
   // FIXME: ugly hack for this for loop to deal with issue 9 which I cannot figure out
   for (var i = 0; i &lt; Math.min(arrayDates.length,20); i++) {
    arrayDateStr.push(replaceBody(arrayDates[i], bodyElement));
   }
   /* The regular expression produced a match, so notify the background page
    * and send the array of dateStrings.
    */
      chrome.extension.sendRequest({dates: JSON.stringify(arrayDateStr)}, function(response){
      });
  }
  else {
      // No match was found.
  }
  </code></pre>
  
  <p>I also have the contentscript send a request to the background.html page to show the page_action button.</p>
  
  <p>background.html:</p>
  
  <pre><code>    &lt;!DOCTYPE html&gt;
  &lt;!--
   * Copyright (c) 2010 The Chromium Authors. All rights reserved.  Use of this
   * source code is governed by a BSD-style license that can be found in the
   * LICENSE file.
  --&gt;
  &lt;html&gt;
    &lt;head&gt;
      &lt;script&gt;
        // Called when a message is passed.  We assume that the content script
        // wants to show the page action.
        function onRequest(request, sender, sendResponse) {
          // Show the page action for the tab that the sender (content script)
          // was on.
          chrome.pageAction.show(sender.tab.id);
    var arrayDateStr = JSON.parse(request.dates);
          // Return nothing to let the connection be cleaned up.
          sendResponse({});
        };
  
        // Listen for the content script to send a message to the background page.
        chrome.extension.onRequest.addListener(onRequest);
  
     // Google Analytics, registers a view once per browser session
     var _gaq = _gaq || [];
       _gaq.push(['_setAccount', 'UA-2551829-4']);
       _gaq.push(['_trackPageview']);
  
       (function() {
         var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
         ga.src = 'https://ssl.google-analytics.com/ga.js';
         var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
       })();
      &lt;/script&gt;
    &lt;/head&gt;
  &lt;/html&gt;
  </code></pre>
  
  <p>I'm now trying to create a popup.html which contains a list of all of the dates on a webpage and again a link to create an event in the users calendar.</p>
  
  <p>popup.html</p>
  
  <pre><code>&lt;head&gt;
  &lt;style&gt;
  body {
    margin: 0px;
    padding: 0px;
  }
  #cal {
    width: 312px;
    height: 312px;
  }
  &lt;/style&gt;
  &lt;script&gt;
  function createLink(dateStr)
  {
   var parElem = document.createElement("P");
   var textNode = document.createTextNode(dateStr);
   var dateLink = document.createElement("A");
   dateLink.target = "_blank";
   dateLink.href = "http://www.google.com/calendar/event?action=TEMPLATE&amp;text=someevent&amp;dates=" + dateStr + "&amp;details=&amp;location=&amp;trp=false&amp;sprop=&amp;sprop=";
   dateLink.appendChild(textNode);
   parElem.appendChild(dateLink);
   return parElem;
  }
  function cal() {
    var arrayDateStr = chrome.extension.getBackgroundPage().arrayDateStr;
    var cal = document.getElementById("cal");
    for(i=0; i&lt;arrayDateStr.length; i++)
    {
     cal.appendChild(createLink(arrayDateStr[i]));
    }
  }
  &lt;/script&gt;
  &lt;/head&gt;
  &lt;body onload="cal()"&gt;
  &lt;p id="cal"&gt;&lt;/p&gt;
  &lt;/body&gt;
  </code></pre>
  
  <p>For some reason
      var arrayDateStr = chrome.extension.getBackgroundPage().arrayDateStr;
  arrayDateStr does not seem to ever be defined.</p>
  
  <p>I'm just really confused right now and cannot find any examples that I understand. I'm thinking I need to do something else with message passing because I don't think getBackgroundPage() would know which tab it should be associated with.</p>
  
  <p>Any ideas or suggestions would be appreciated. Thank you.</p>