title: Function works in Chrome/Safari but not Firefox
body: <p>So I have a table where you can check a table row and it will get the values of each cell in that row and also display another column named <code>Quantity #</code>. The <code>Quantity #</code> column contains a <code>type="number"</code> input. After entering a number, a user will be able to refresh the page and the <code>Quantity #</code> column and the value entered into the input will both remain visible. A user can also hit a "Checkout" button and it will post that data to an email body.</p>
  
  <p>That all works great in Safari and Google Chrome. However, in Firefox, if you enter a value into the input and then refresh for example, the value will no longer be in the input. Also, if you hit the Checkout button and it pastes the data to the email, it will not paste the input value either like it does in Safari/Chrome.</p>
  
  <p>Why is this and what can I do to fix this problem in Firefox?</p>
  
  <p>JavaScript:</p>
  
  <pre><code>$(function($) {
      var RowData = (function(storage, storageKey) {
          var rowData = readFromSession();
          var dataItems = ['loc', 'rp-code', 'sku', 'special-id', 'description', 'quantity', 'unit'];
          var emailDelimiters = {
              'row': '%0D%0A',
              'dataItem': '\xa0\xa0'
          };
  
          function readFromSession() {
              return JSON.parse(storage.getItem(storageKey) || '{}');
          }
          function writeToSession() {
              storage.setItem(storageKey, JSON.stringify(rowData));
          }
          function writeRow(tr) {
              var $tr = $(tr),
                  id = $tr.prop('id');
              if($tr.find('.check').is(':checked')) {
                  rowData[id] = {};
                  for(var i=0; i&lt;dataItems.length; i++) {
                      rowData[id][dataItems[i]] = $tr.find('.' + dataItems[i]).text();
                  }
                  rowData[id].quantity_num = $tr.find('.spinner').val();
              } else {
                  delete rowData[id];
              }
              writeToSession();
          }
          function readRow(tr) {
              // restore tr's checkbox and spinner value from stored data
              var $tr = $(tr),
                  id = $tr.prop('id'),
                  row = rowData[id];
              if(row) {
                  $tr.find('.check').prop('checked', true).end()
                       // .find('.spinner').spinner('value', row.quantity_num); // if using spinner widget
                       .find('.spinner').val(row.quantity_num); // if using HTML5 &lt;input type="number"&gt;
              }
          }
          function toEmailString() {
              return $.map(rowData, function(row, id) {
                  return $.map(row, window.encodeURIComponent).join(emailDelimiters.dataItem);
              }).join(emailDelimiters.row);
          }
          // selectively expose functions as methods of RowData
          return {
              'writeRow': writeRow,
              'readRow': readRow, 
              'toEmailString': toEmailString
          };
      })(window.sessionStorage, 'checkedRowData');
  
      $('#merchTable').on('change', '.check', function() { // on changing a table row ...
          RowData.writeRow($(this).closest('tr').get(0)); // ... set the corresponding row object in RowData and sessionStorage
      }).on('blur', '.spinner', function() { // on leaving a spinner widget
          RowData.writeRow($(this).closest('tr').get(0));
      });
      $('#checkout').on('click', function() { // on clicking the [Checkout] button
          var link = "mailto:me@example.com" + "?subject=" + encodeURIComponent("Order") + "&amp;body=" + RowData.toEmailString();
          console.log(link);
          window.location.href = link;
      });
  
      // Call this function on completion of every pagination/search
      function restoreVisibleRows() {
          $('#merchTable tbody tr').get().forEach(RowData.readRow);
      }
  
      restoreVisibleRows();
  
  });
  </code></pre>
  
  <p>JavaScript that keeps input value and quantity # column displayed on refresh:</p>
  
  <pre><code>$(function(){
      var showQuantityHeader = false;
      $(':checkbox').each(function() {
          // Iterate over the checkboxes and set their "check" values based on the session data
          var $el = $(this);
          //console.log('element id: ',$el.prop('id'),' sessionStorage[id]: ',sessionStorage[$el.prop('id')]);
          $el.prop('checked', sessionStorage[$el.prop('id')] === 'true');
          if ($el.prop('checked')) {          
              //show the quantity cell in the column under header with class num
              $el.closest('tr').find('td.quantity_num').toggle(this.checked);
              showQuantityHeader = true;
              //setupSpinner(this);
              var quantity = sessionStorage['value_'+$el.prop('id')];
  
          }
      });
  
      if (showQuantityHeader) {
              $('#merchTable').find('th.num').show();
          //console.log('header with class num: ',$('#merchTable').find('th.num'));
      }
  
      $('input:checkbox').on('change', function() {
          // save the individual checkbox in the session inside the `change` event, 
          // using the checkbox "id" attribute
          var $el = $(this);
          sessionStorage[$el.prop('id')] = $el.is(':checked');
          console.log($el);
      });
  });
  </code></pre>
  
  <p>HTML:</p>
  
  <pre><code>&lt;section id="checkout-btn"&gt; 
  &lt;button id="checkout" name="order"&gt;Checkout&lt;/button&gt;
  &lt;/section&gt;
  
  &lt;br&gt;
  
  &lt;table id="merchTable" cellspacing="5" class="sortable"&gt;
      &lt;thead&gt;
          &lt;tr class="ui-widget-header"&gt;
              &lt;th class="sorttable_nosort"&gt;&lt;/th&gt;
              &lt;th class="sorttable_nosort"&gt;Loc&lt;/th&gt;
              &lt;th class="merchRow"&gt;Report Code&lt;/th&gt;
              &lt;th class="merchRow"&gt;SKU&lt;/th&gt;
              &lt;th class="merchRow"&gt;Special ID&lt;/th&gt;
              &lt;th class="merchRow"&gt;Description&lt;/th&gt;
              &lt;th class="merchRow"&gt;Quantity&lt;/th&gt;
              &lt;th class="sorttable_nosort"&gt;Unit&lt;/th&gt;
              &lt;th style="display: none;" class="num"&gt;Quantity #&lt;/th&gt;
          &lt;/tr&gt;
      &lt;/thead&gt;
      &lt;tbody&gt;
  
          &lt;?php foreach ($dbh-&gt;query($query) as $row) {?&gt;
  
          &lt;tr id="&lt;?php echo intval ($row['ID'])?&gt;"&gt;
              &lt;td class="ui-widget-content"&gt;&lt;input type="checkbox" class="check" name="check" id="checkid-&lt;?php echo intval ($row['ID'])?&gt;"&gt;&lt;/td&gt;
              &lt;td class="loc ui-widget-content" data-loc="&lt;?php echo $row['Loc'] ?&gt;"&gt;&lt;input type="hidden"&gt;&lt;?php echo $row['Loc'];?&gt;&lt;/td&gt;
              &lt;td class="rp-code ui-widget-content" align="center" data-rp-code="&lt;?php echo $row['Rp-Code'] ?&gt;" id="rp-code-&lt;?php echo intval ($row['Rp-Code'])?&gt;"&gt;&lt;?php echo $row['Rp-Code'];?&gt;&lt;/td&gt;
              &lt;td class="sku ui-widget-content" data-sku="&lt;?php echo $row['SKU'] ?&gt;" id="sku-&lt;?php echo intval ($row['SKU'])?&gt;"&gt;&lt;?php echo $row['SKU'];?&gt;&lt;/td&gt;
              &lt;td class="special-id ui-widget-content" data-special-id="&lt;?php echo $row['Special-ID'] ?&gt;" align="center" id="special-id-&lt;?php echo intval ($row['Special-ID'])?&gt;"&gt;&lt;?php echo $row['Special-ID'];?&gt;&lt;/td&gt;
              &lt;td class="description ui-widget-content" data-description="&lt;?php echo htmlspecialchars($row['Description']) ?&gt;" id="description-&lt;?php echo intval ($row['Description'])?&gt;"&gt;&lt;?php echo $row['Description'];?&gt;&lt;/td&gt;
              &lt;td class="quantity ui-widget-content" data-quantity="&lt;?php echo $row['Quantity'] ?&gt;" align="center" id="quantity-&lt;?php echo intval ($row['Quantity'])?&gt;"&gt;&lt;?php echo $row['Quantity'];?&gt;&lt;/td&gt;
              &lt;td class="unit ui-widget-content" data-unit="&lt;?php echo $row['Unit'] ?&gt;" id="unit-&lt;?php echo intval ($row['Unit'])?&gt;"&gt;&lt;?php echo $row['Unit'];?&gt;&lt;/td&gt;
              &lt;td style="display: none;" class="quantity_num ui-widget-content"&gt;&lt;input type="number" min="1" max="&lt;?php echo $row['Quantity'];?&gt;" step="1" style="width: 100px;" class="spinner" /&gt;&lt;/td&gt;
          &lt;/tr&gt;
  
      &lt;?php } ?&gt;
  
      &lt;/tbody&gt;
  &lt;/table&gt;
  </code></pre>
  
  <p>EDIT:
  <a href="https://i.stack.imgur.com/x9EU2.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/x9EU2.png" alt="Console errors"></a></p>