docs: function ChoiceTableGroup(options) {
          var that;
          that = this;
  
          /**
           * ### ChoiceTableGroup.dl
           *
           * The clickable table containing all the cells
           */
          this.table = null;
  
          /**
           * ### ChoiceTableGroup.trs
           *
           * Collection of all trs created
           *
           * Useful when shuffling items/choices
           *
           * @see ChoiceTableGroup.shuffle
           */
          this.trs = [];
  
          /**
           * ## ChoiceTableGroup.listener
           *
           * The listener function
           *
           * @see GameChoice.enable
           * @see GameChoice.disable
           */
          this.listener = function(e) {
              var name, value, item, td, oldSelected;
              var time;
  
              // Relative time.
              if ('string' === typeof that.timeFrom) {
                  time = node.timer.getTimeSince(that.timeFrom);
              }
              // Absolute time.
              else {
                  time = Date.now ? Date.now() : new Date().getTime();
              }
  
              e = e || window.event;
              td = e.target || e.srcElement;
  
              // Not a clickable choice.
              if (!td.id || td.id === '') return;
  
              // Not a clickable choice.
              if (!that.choicesById[td.id]) return;
  
              // Id of elements are in the form of name_value or name_item_value.
              value = td.id.split(that.separator);
  
              // Separator not found, not a clickable cell.
              if (value.length === 1) return;
  
              name = value[0];
              value = value[1];
  
              item = that.itemsById[name];
  
              // Not a clickable cell.
              if (!item) return;
  
              item.timeCurrentChoice = time;
  
              // One more click.
              item.numberOfClicks++;
  
              // If only 1 selection allowed, remove selection from oldSelected.
              if (!item.selectMultiple) {
                  oldSelected = item.selected;
                  if (oldSelected) J.removeClass(oldSelected, 'selected');
  
                  if (item.isChoiceCurrent(value)) {
                      item.unsetCurrentChoice(value);
                  }
                  else {
                      item.currentChoice = value;
                      J.addClass(td, 'selected');
                      item.selected = td;
                  }
              }
  
              // Remove any warning/error from form on click.
              if (that.isHighlighted()) that.unhighlight();
          };
  
          /**
           * ### ChoiceTableGroup.mainText
           *
           * The main text introducing the choices
           *
           * @see ChoiceTableGroup.spanMainText
           */
          this.mainText = null;
  
          /**
           * ### ChoiceTableGroup.spanMainText
           *
           * The span containing the main text
           */
          this.spanMainText = null;
  
          /**
           * ### ChoiceTableGroup.hint
           *
           * An additional text with information about how to select items
           *
           * If not specified, it may be auto-filled, e.g. '(pick 2)'.
           *
           * @see Feedback.texts.autoHint
           */
          this.hint = null;
  
          /**
           * ### ChoiceTableGroup.items
           *
           * The array of available items
           */
          this.items = null;
  
          /**
           * ### ChoiceTableGroup.itemsById
           *
           * Map of items ids to items
           */
          this.itemsById = {};
  
          /**
           * ### ChoiceTableGroup.itemsMap
           *
           * Maps items ids to the position in the items array
           */
          this.itemsMap = {};
  
          /**
           * ### ChoiceTableGroup.choices
           *
           * Array of default choices (if passed as global parameter)
           */
          this.choices = null;
  
          /**
           * ### ChoiceTableGroup.choicesById
           *
           * Map of items choices ids to corresponding cell
           *
           * Useful to detect clickable cells.
           */
          this.choicesById = {};
  
          /**
           * ### ChoiceTableGroup.itemsSettings
           *
           * The array of settings for each item
           */
          this.itemsSettings = null;
  
          /**
           * ### ChoiceTableGroup.order
           *
           * The current order of display of choices
           *
           * May differ from `originalOrder` if shuffled.
           *
           * @see ChoiceTableGroup.originalOrder
           */
          this.order = null;
  
          /**
           * ### ChoiceTableGroup.originalOrder
           *
           * The initial order of display of choices
           *
           * @see ChoiceTable.order
           */
          this.originalOrder = null;
  
          /**
           * ### ChoiceTableGroup.shuffleItems
           *
           * If TRUE, items are inserted in random order
           *
           * @see ChoiceTableGroup.order
           */
          this.shuffleItems = null;
  
          /**
           * ### ChoiceTableGroup.requiredChoice
           *
           * The number of required choices.
           */
          this.requiredChoice = null;
  
          /**
           * ### ChoiceTableGroup.orientation
           *
           * Orientation of display of items: vertical ('V') or horizontal ('H')
           *
           * Default orientation is horizontal.
           */
          this.orientation = 'H';
  
          /**
           * ### ChoiceTableGroup.group
           *
           * The name of the group where the table belongs, if any
           */
          this.group = null;
  
          /**
           * ### ChoiceTableGroup.groupOrder
           *
           * The order of the choice table within the group
           */
          this.groupOrder = null;
  
          /**
           * ### ChoiceTableGroup.freeText
           *
           * If truthy, a textarea for free-text comment will be added
           *
           * If 'string', the text will be added inside the the textarea
           */
          this.freeText = null;
  
          /**
           * ### ChoiceTableGroup.textarea
           *
           * Textarea for free-text comment
           */
          this.textarea = null;
  
          // Options passed to each individual item.
  
          /**
           * ### ChoiceTableGroup.timeFrom
           *
           * Time is measured from timestamp as saved by node.timer
           *
           * Default event is a new step is loaded (user can interact with
           * the screen). Set it to FALSE, to have absolute time.
           *
           * This option is passed to each individual item.
           *
           * @see mixinSettings
           *
           * @see node.timer.getTimeSince
           */
          this.timeFrom = 'step';
  
          /**
           * ### ChoiceTableGroup.selectMultiple
           *
           * If TRUE, it allows to select multiple cells
           *
           * This option is passed to each individual item.
           *
           * @see mixinSettings
           */
          this.selectMultiple = null;
  
          /**
           * ### ChoiceTableGroup.renderer
           *
           * A callback that renders the content of each cell
           *
           * The callback must accept three parameters:
           *
           *   - a td HTML element,
           *   - a choice
           *   - the index of the choice element within the choices array
           *
           * and optionally return the _value_ for the choice (otherwise
           * the order in the choices array is used as value).
           *
           * This option is passed to each individual item.
           *
           * @see mixinSettings
           */
          this.renderer = null;
  
          /**
           * ### ChoiceTableGroup.separator
           *
           * Symbol used to separate tokens in the id attribute of every cell
           *
           * Default ChoiceTableGroup.separator
           *
           * This option is passed to each individual item.
           *
           * @see mixinSettings
           */
          this.separator = ChoiceTableGroup.separator;
  
          /**
           * ### ChoiceTableGroup.shuffleChoices
           *
           * If TRUE, choices in items are shuffled
           *
           * This option is passed to each individual item.
           *
           * @see mixinSettings
           */
          this.shuffleChoices = null;
      }