Datatables with editable child tables using a hidden table to coordinate column widths

This is a nested table with shared headers, with a parent row that uses colspan for the wide message field, a child row for the wide pattern field, and another child row with a table for the details. The width of the top-level headers, and of the detail table headers are set by finding the longest strings from each column, adding them to a hidden datatable, drawing the table, checking the sizes, then updating the top-level column and detail table columns to match the hidden table. A bit convoluted, and very hackish implementation, but it works.

by Christopher Austin

HTML

<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
<link rel="stylesheet" href="https://cdn.datatables.net/1.10.1/css/jquery.dataTables.css">
<script src="https://cdn.datatables.net/1.10.1/js/jquery.dataTables.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mockjax/1.6.2/jquery.mockjax.min.js"></script>
<script src="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
        
<table id="messages" class="table compact row-border order-column" cellspacing="0" width="100%">
  <thead>
      <tr>
        <th>ID</th>
        <th>Group</th>
        <th>Key</th>
        <th>Message</th>
        <th>Category</th>
        <th>Type</th>
        <th>Action</th>
        <th>Object</th>
        <th>Context</th>
        <th>Status</th>
        <th>Reason</th>
      </tr>
  </thead>
</table>

        
<table id="width-table" class="table compact row-border order-column"  cellspacing="0" width="100%">
  <thead>
      <tr>
        <th>ID</th>
        <th>Group</th>
        <th>Key</th>
        <th>Category</th>
        <th>Type</th>
        <th>Action</th>
        <th>Object</th>
        <th>Context</th>
        <th>Status</th>
        <th>Reason</th>
      </tr>
  </thead>
</table>

JavaScript

console.clear()
var dataSet = [
    {
      "id": 9973,
      "vendorCategory": "Security-Auditing",
      "key": "4776",
      "message": "The domain controller attempted to validate the credentials for an account.\n\nAuthentication Package: %1\nLogon Account: %2\nSource Workstation: %3\nError Code: %4",
      "patterns": [
        {
          "id": 5237,
          "idx": 1,
          "category": "access",
          "type": "user",
          "action": "login",
          "status": "success",
          "pattern": "(?<detail>The domain controller attempted to validate the credentials for an account)\\. Authentication Package: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0 (?:Logon Account: (?<user>.+?)|Logon Account:) Source Workstation: (?:(?<source>.*?) )?Error Code: (?<result>0x[0-9A-Fa-f]+)",
          "fieldConditions": [
          {
          	"field":"result",
            "match":"0x0",
            "status":"success"
          },
          {
          	"field":"result",
            "match":"0xC0000064",
            "status":"failure",
            "reason":"invalid-user"
          },
          {
          	"field":"result",
            "match":".+",
            "status":"failure"
          }
          ]
        },

      ],
      "DT_RowId": "row_1"
    },
]
$.mockjax({
  url: 'data.json',
  responseTime: 10,
  responseText: {
    "data": dataSet
  }
});

var dt
/*
 * Join the sorted set of distinct field values from row using the provided separator
 */
function separatedFieldValues(row, field, sep) {
  return jQuery.unique(
    row.patterns.map(   function(o) {return o[field]})
    .filter(function(o) {return o != null})
    .sort()
  ).join(sep)
}
function encoded(x) {
  if (x === null) {
    return ''
  }
  return $('<div/>').text(x).html()
}

function recordLongest(key, data, longest) {
  if (!data[key]) {
    return
  }
  if (!longest[key]) {
    longest[key] = data[key] 
  }
  else {
    if (longest[key].length < data[key].length) {
      longest[key] =...