title: List view getListItemXmlAttributes method fails with child publication items
body: <p>I have created a JS class to populate SG/Folder list view data, when items are modified. (<a href="http://jaimesantosalcon.blogspot.com/2012/04/sdl-tridion-2011-data-extenders-real.html">As per Jaime's approach)</a>
  Everything works great when I operate on items in the publication they're created in.</p>
  
  <p><strong>Ex:</strong> I open a component or page and the custom <code>locked by</code> column immediately updates and shows my user name.</p>
  
  <p>However, when I go to a child publication and repeat that process, I get the window asking if I want to localize or edit the parent item. If I select to edit the parent window, the code doesn't work. I haven't quite figured it out yet with initial debugging. Chrome seems to swallow the error, Firefox gives me a cryptic:</p>
  
  <blockquote>
    <p>Timestamp: 6/22/2012 3:42:54 PM</p>
    
    <p>Error: uncaught exception: [Exception... "Component returned failure code: 0x80004002
     (NS_NOINTERFACE) [nsIWebProgress.DOMWindow]"  nsresult: "0x80004002 (NS_NOINTERFACE)" 
     location: "JS frame :: chrome://browser/content/tabbrowser.xml ::  :: line 545" 
     data: no]</p>
  </blockquote>
  
  <p>Does anyone have any initial ideas? I'll try to post some code later on...</p>
  
  <p>Code from PageEx.js:</p>
  
  <pre class="lang-js prettyprint-override"><code>Type.registerNamespace("MyCompany.Tridion.RTFExtensions");
  
  /*
  * Constructor
  */
  
  MyCompany.Tridion.RTFExtensions.PageEx = function (id) {
      Type.enableInterface(this, "MyCompany.Tridion.RTFExtensions.PageEx");
      this.addInterface("Tridion.ContentManager.Page", [id]);
      var p = this.properties;
      p.versionNumberString = undefined;
      p.modifiedBy = undefined;
      p.lockedBy = undefined;
      p.approvalStatus = undefined;
      p.publishDate = undefined;
      p.previousVersion = undefined;
      p.previousApprovalStatus = undefined;
      p.customModifiedDate = undefined;
      p.initialModifierUserName = undefined;
  };
  
  /*
  * sends the list xml string for the item 
  */
  MyCompany.Tridion.RTFExtensions.PageEx.prototype.getListItemXmlAttributes = function (customAttributes) {
      var attribs = {};
      $extUtils.getListItemXmlAttributes(customAttributes,this, attribs);
      return this.callBase("Tridion.ContentManager.Page", "getListItemXmlAttributes", [attribs]);
  };
  
  
  /*
  * This method gets called when an item is opened from list view. node parameter has the information
  * displayed in the list view as attributes. We are getting cutom data extender column information 
  * from this xml node and storing it in this class member for returning it from getListItemXmlAttributes method
  */
  MyCompany.Tridion.RTFExtensions.PageEx.prototype.setDataFromList = function (node, parentId, timeStamp) {
      $extUtils.setDataFromList(node,parentId,timeStamp,this);
      this.callBase("Tridion.ContentManager.Page", "setDataFromList", [node, parentId, timeStamp]);
  };
  
  /* 
  * Gets item icon 
  */
  MyCompany.Tridion.RTFExtensions.PageEx.prototype.getItemIcon = function () {
      var icon = this.callBase(this.defaultBase, "getItemIcon");
      return icon;
  };
  </code></pre>
  
  <p>Code from utils.js:</p>
  
  <pre class="lang-js prettyprint-override"><code>// reloads the list view for the given id (used in list view data refresh when JS cant get the required data without reloading)
  MyCompany.Tridion.RTFExtensions.Utilities.reloadListView = function (listTcmId) {
      var registry = $models.getListsRegistry();
      for(var key in registry)
      {
          var entry = $models.getItem(registry[key]);
          if (entry &amp;&amp; entry.getParentId() == listTcmId)
          {
             entry.unload();
             return true;
          }
      }
      return false;
  }
  
  /*
  * This method gets called when an item is opened from list view. node parameter has the information
  * displayed in the list view as attributes. We are getting cutom data extender column information 
  * from this xml node and storing it in this class member for returning it from getListItemXmlAttributes method
  */
  MyCompany.Tridion.RTFExtensions.Utilities.setDataFromList = function (node, parentId, timeStamp, itemClicked) {
      var p = itemClicked.properties;
  
      if (!timeStamp || timeStamp &gt; itemClicked.getTimeStamp()) {
          var tmp;
          if (tmp = node.getAttribute('Version')) {
              p.versionNumberString = tmp;
              p.previousVersion = tmp;
          }
          if (tmp = node.getAttribute('ModifiedBy')) {
              p.modifiedBy = tmp;
              p.initialModifierUserName = tmp;
          }
          if (tmp = node.getAttribute('LockedBy')) {
              p.lockedBy = tmp;
          }
          if (tmp = node.getAttribute('ApprovalStatus')) {
              p.approvalStatus = tmp;
              p.previousApprovalStatus = tmp;
          }
          if (tmp = node.getAttribute('PublishDate')) {
              p.publishDate = tmp;
          }
          if (p.customModifiedDate === undefined) {
              if (tmp = node.getAttribute('Modified')) {
                  p.customModifiedDate = tmp;
              }
          }
      }
  }
  
  /*
  * sends the list xml string for the item in the list view.
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListItemXmlAttributes = function (customAttributes, listViewObject,attribs) {
      var p = listViewObject.properties;
      $extUtils.getListViewItemLockedByName(p,listViewObject);
  
      if (customAttributes) {
          for (var attr in customAttributes) {
              attribs[attr] = customAttributes[attr];
          }
      }
  
      attribs["Version"] = $extUtils.getListViewItemUpdatedVersion(p,listViewObject);
      //modified name has to come after the version update...
      $extUtils.getListViewItemModifiedByName(p,listViewObject);
      attribs["ApprovalStatus"] = $extUtils.getListViewItemApprovalStatus(p,listViewObject);  
      attribs["PublishDate"] = $extUtils.getListViewItemPublishDate(p,listViewObject);
  
      //set default values
      if (p.versionNumberString != undefined) {
          var iResult = p.versionNumberString.localeCompare(p.previousVersion);
          if (p.previousVersion === undefined || iResult &gt; 0) {
              //it's been updated!
              p.previousVersion = p.versionNumberString;
              p.previousApprovalStatus = p.approvalStatus;
  
              //also need to update modified date
              p.customModifiedDate = $extUtils.getListViewItemUpdatedModifiedDate(p,listViewObject);
              p.initialModifierUserName = p.modifiedBy;
          }
  
      }
      attribs["Modified"] = p.customModifiedDate;
      attribs["LockedBy"] = p.lockedBy;
      attribs["ModifiedBy"] = p.modifiedBy;
  
  };
  
  /*
  * This method sets the property of the Revisor owner on the item in the list view. however, if it's not the current user
  * we have no way to look that up in JS so we have to reload the list view.
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemModifiedByName = function (p,listViewObject) {
      var p = listViewObject.properties;
      var xmlDoc = listViewObject.getXmlDocument();
      if (xmlDoc) {
          //modifier should always exist...
          var modifierId = $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:VersionInfo/tcm:Revisor/@xlink:title");
          if (modifierId != undefined) {
              var u = Tridion.UI.UserSettings.getJsonUserSettings(true);
              if (modifierId == u.User.Data.Name) {
                  var strDescription = u.User.Data.Description.split('(');
                  p.modifiedBy = strDescription[0];
                  return;
              } else {
                  //we're in trouble...
                  //let's hope it's the initial modifier we had...
                  if (p.previousVersion == p.versionNumberString) {
                      //whew...
                      p.modifiedBy = p.initialModifierUserName;
                      return;
                  }
  
                  if (!$extUtils.reloadListView(listViewObject.getOrganizationalItemId())) {
                      //hrm. something failed on the reload? not sure what else to do:
                      p.modifiedBy = modifierId;
                  }
              }
          } else {
              //shouldn't ever happen.
              p.modifiedBy = "";
              return;
          }
      }
  
  };
  
  /*
  * This method sets the property of the lock owner on the item in the list view. however, if it's not the current user
  * we have no way to look that up in JS so we have to reload the list view.
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemLockedByName = function (p,listViewObject) {
      var xmlDoc = listViewObject.getXmlDocument();
      if (xmlDoc) {
          //this will be user id. no sense getting tcmid... can't look it up without async call
          var lockedUserId = $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:VersionInfo/tcm:ItemLock/tcm:User/@xlink:title");
          if (lockedUserId != undefined) {
              //see if it's the current user. most likely...
              var u = Tridion.UI.UserSettings.getJsonUserSettings(true);
              if (lockedUserId == u.User.Data.Name) {
                  var strDescription = u.User.Data.Description.split('(');
                  p.lockedBy = strDescription[0];
                  return;
              }
              //it's not the current user. no synch way to do what we want, plus the JS call doesn't get the workflow version anyway. refresh the parent view
              if (!$extUtils.reloadListView(listViewObject.getOrganizationalItemId())) {
                  //hrm. something failed on the reload? not sure what else to do:
                  p.lockedBy = lockedUserId;
              }
          } else {
              //clear it out since there's no lock owner
              p.lockedBy = "";
          }
      }
  };
  
  /*
  * Gets the ApprovalStatus from the item
  * This makes absolutely no sense... but for some reason the approval status gets wiped out when this method
  * enters. so I had to use a "previous approval status" variable to maintain it. no idea why. I don't see anything
  * else that should be touching it... but clearly something clears it out.
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemApprovalStatus = function (p,listViewObject) {
      //check if the item has actually been modified.
      if (p.versionNumberString != p.previousVersion) {
          var xmlDoc = listViewObject.getXmlDocument();
          if (xmlDoc) {
              p.approvalStatus = $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:Data/tcm:ApprovalStatus/@xlink:title");
          }
      } else {
          p.approvalStatus = p.previousApprovalStatus;
      }
      if (p.approvalStatus === undefined || p.approvalStatus.toUpperCase() == 'UNAPPROVED') {
          var foo = p.approvalStatus;
          p.approvalStatus = 'WIP';
      }
      return p.approvalStatus;
  };
  
  
  /*
  * Gets the PublishDate from the item list view
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemPublishDate = function (p,listViewObject) {
      //modification won't alter publish date.
      var p = listViewObject.properties;
      return p.publishDate;
  };
  
  
  /*
  *   get the modified date for the workflow version, overwrite OOB since that uses last major version
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemUpdatedModifiedDate = function (p,listViewObject) {
      var xmlDoc = listViewObject.getXmlDocument();
      var modDate = $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:VersionInfo/tcm:RevisionDate");
      return modDate;
  }
  
  
  /*
  * Gets the updated Version information from the item
  */
  MyCompany.Tridion.RTFExtensions.Utilities.getListViewItemUpdatedVersion = function (p,listViewObject) {
      var p = listViewObject.properties;
      var xmlDoc = listViewObject.getXmlDocument();
      var newVersionString = undefined;
      if (xmlDoc) {
          newVersionString = String.format("{0}.{1}", $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:VersionInfo/tcm:Version"), $xml.getInnerText(xmlDoc, "/tcm:*/tcm:Info/tcm:VersionInfo/tcm:Revision"));
      }
      if (newVersionString != undefined) {
          //want to ensure we're getting a LATER version than we had (because it will try to load the non-workflow version afterwards...
          var iResult = newVersionString.localeCompare(p.previousVersion);
          if (p.previousVersion === undefined || iResult &gt; 0) {
              p.versionNumberString = newVersionString;
          } else {
              p.versionNumberString = p.previousVersion;
          }
      } else {
          p.versionNumberString = p.previousVersion;
      }
      return p.versionNumberString;
  };
  
  
  
  function launchPopup(winURL, winName, winFeatures, winObj) {
      // this will hold our opened window
      var theWin;
      // first check to see if the window already exists
      if (winObj != null) {
          // the window has already been created, but did the user close it?
          // if so, then reopen it. Otherwise make it the active window.
          if (!winObj.closed) {
              winObj.focus();
              return winObj;
          }
          // otherwise fall through to the code below to re-open the window
      }
      // if we get here, then the window hasn't been created yet, or it
      // was closed by the user.
      theWin = window.open(winURL, winName, winFeatures);
      return theWin;
  }
  
  var $extUtils = MyCompany.Tridion.RTFExtensions.Utilities;
  </code></pre>