%label{ :for => "source_plates" } Source plates
= text_area_tag "source_plates", '', :rows => 5,:cols => 17

:javascript
 $('#source_plates').focus();
 $('#source_plates').trigger('change');
%label{ :for => "source_plates" } Source plates (20 max.)
= text_area_tag "source_plates", '', :rows => 5,:cols => 17
.live_results#barcodes_scanned 0 barcodes

:javascript
  $('#source_plates').focus();
  $('#source_plates').trigger('change');
  $('#source_plates').keyup(recalcNumBarcodes);

  function recalcNumBarcodes(){
    const num_barcodes = find_number_barcodes($('#source_plates').val());
    const colour = num_barcodes > 20 ? 'red' : 'black';

    $('#barcodes_scanned').text(num_barcodes + ' barcodes').css('color', colour);
  }

  function find_number_barcodes(text){
    const barcodes_list_no_blanks = text.split(/\s+/).filter(barcode => Boolean(barcode));
    const barcodes_list_unique = [...new Set(barcodes_list_no_blanks)];
    return barcodes_list_unique.length;
  }
Add a live count - number of barcodes scanned - goes red when over limit - also (20 max.) in brackets to show the limit
Add a live count - number of barcodes scanned - goes red when over limit
- also (20 max.) in brackets to show the limit
