<commit_before>define(['dojo/_base/declare',
        'dojo/_base/array',
        'dojo/_base/lang',
        'dojo/dom-construct',
        'dojo/query',
        'dojo/on',
        'dojo/json',

        'dijit/TitlePane',
        'dijit/layout/ContentPane',

        'JBrowse/Util',
        './_TextFilterMixin'
       ],
       function(
           declare,
           array,
           lang,
           dom,
           query,
           on,
           JSON,

           TitlePane,
           ContentPane,

           Util,
           _TextFilterMixin
       ) {

return declare(
    'JBrowse.View.TrackList.Hierarchical',
    [ ContentPane, _TextFilterMixin ],
    {

    region: 'left',
    splitter: true,
    style: 'width: 25%',

    id: 'hierarchicalTrackPane',
    baseClass: 'jbrowseHierarchicalTrackSelector',

    categoryFacet: 'category',

    constructor: function( args ) {
        this.categories = {};

        this._loadState();
    },
    postCreate: function() {
        this.placeAt( this.browser.container );

        // subscribe to commands coming from the the controller
        this.browser.subscribe( '/jbrowse/v1/c/tracks/show',
                                lang.hitch( this, 'setTracksActive' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/hide',
                                lang.hitch( this, 'setTracksInactive' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/new',
                                lang.hitch( this, 'addTracks' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/replace',
                                lang.hitch( this, 'replaceTracks' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/delete',
                                lang.hitch( this, 'deleteTracks' ));
    },

    buildRendering: function() {
        this.inherited(arguments);

        var topPane = new ContentPane({ className: 'header' });
        this.addChild( topPane );
        dom.create(
            'h2',
            { className: 'title',
              innerHTML: 'Available Tracks'
            },
            topPane.containerNode );

        this._makeTextFilterNodes(
            dom.create('div',
                       { className: 'textfilterContainer' },
                       topPane.containerNode )
        );
        this._updateTextFilterControl();
    },

    startup: function() {
        this.inherited( arguments );

        var tracks = [];
        var thisB = this;
        var categoryFacet = this.get('categoryFacet');
        var sorter = this.browser.config.sortHierarchicalTrackList ? 
                             [ { attribute: this.get('categoryFacet').toLowerCase()},
                               { attribute: 'key' },
                               { attribute: 'label' }
                             ] : undefined;
        this.get('trackMetaData').fetch(
            { onItem: function(i) {
                  if( i.conf )
                      tracks.push( i );
              },
              onComplete: function() {
                  // make a pane at the top to hold uncategorized tracks
                  thisB.categories.Uncategorized =
                      { pane: new ContentPane({ className: 'uncategorized' }).placeAt( thisB.containerNode ),
                        tracks: {},
                        categories: {}
                      };

                  thisB.addTracks( tracks, true );

                  // hide the uncategorized pane if it is empty
                  if( ! thisB.categories.Uncategorized.pane.containerNode.children.length ) {
                      //thisB.removeChild( thisB.categories.Uncategorized.pane );
                      thisB.categories.Uncategorized.pane.domNode.style.display = 'none';
                  }
              },
              sort: sorter 
            });
    },

    addTracks: function( tracks, inStartup ) {
        this.pane = this;
        var thisB = this;
       
        array.forEach( tracks, function( track ) {
            var trackConf = track.conf || track;

            var categoryFacet = this.get('categoryFacet');
            var categoryNames = (
                trackConf.metadata && trackConf.metadata[ categoryFacet ]
                    || trackConf[ categoryFacet ]
                    || 'Uncategorized'
            ).split(/\s*\/\s*/);<commit_msg>Load category from trackMetaData in addition to existing loading from file configurations<commit_after>define(['dojo/_base/declare',
        'dojo/_base/array',
        'dojo/_base/lang',
        'dojo/dom-construct',
        'dojo/query',
        'dojo/on',
        'dojo/json',

        'dijit/TitlePane',
        'dijit/layout/ContentPane',

        'JBrowse/Util',
        './_TextFilterMixin'
       ],
       function(
           declare,
           array,
           lang,
           dom,
           query,
           on,
           JSON,

           TitlePane,
           ContentPane,

           Util,
           _TextFilterMixin
       ) {

return declare(
    'JBrowse.View.TrackList.Hierarchical',
    [ ContentPane, _TextFilterMixin ],
    {

    region: 'left',
    splitter: true,
    style: 'width: 25%',

    id: 'hierarchicalTrackPane',
    baseClass: 'jbrowseHierarchicalTrackSelector',

    categoryFacet: 'category',

    constructor: function( args ) {
        this.categories = {};

        this._loadState();
    },
    postCreate: function() {
        this.placeAt( this.browser.container );

        // subscribe to commands coming from the the controller
        this.browser.subscribe( '/jbrowse/v1/c/tracks/show',
                                lang.hitch( this, 'setTracksActive' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/hide',
                                lang.hitch( this, 'setTracksInactive' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/new',
                                lang.hitch( this, 'addTracks' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/replace',
                                lang.hitch( this, 'replaceTracks' ));
        this.browser.subscribe( '/jbrowse/v1/c/tracks/delete',
                                lang.hitch( this, 'deleteTracks' ));
    },

    buildRendering: function() {
        this.inherited(arguments);

        var topPane = new ContentPane({ className: 'header' });
        this.addChild( topPane );
        dom.create(
            'h2',
            { className: 'title',
              innerHTML: 'Available Tracks'
            },
            topPane.containerNode );

        this._makeTextFilterNodes(
            dom.create('div',
                       { className: 'textfilterContainer' },
                       topPane.containerNode )
        );
        this._updateTextFilterControl();
    },

    startup: function() {
        this.inherited( arguments );

        var tracks = [];
        var thisB = this;
        var categoryFacet = this.get('categoryFacet');
        var sorter = this.browser.config.sortHierarchicalTrackList ? 
                             [ { attribute: this.get('categoryFacet').toLowerCase()},
                               { attribute: 'key' },
                               { attribute: 'label' }
                             ] : undefined;
        this.get('trackMetaData').fetch(
            { onItem: function(i) {
                  if( i.conf )
                      tracks.push( i );
              },
              onComplete: function() {
                  // make a pane at the top to hold uncategorized tracks
                  thisB.categories.Uncategorized =
                      { pane: new ContentPane({ className: 'uncategorized' }).placeAt( thisB.containerNode ),
                        tracks: {},
                        categories: {}
                      };

                  thisB.addTracks( tracks, true );

                  // hide the uncategorized pane if it is empty
                  if( ! thisB.categories.Uncategorized.pane.containerNode.children.length ) {
                      //thisB.removeChild( thisB.categories.Uncategorized.pane );
                      thisB.categories.Uncategorized.pane.domNode.style.display = 'none';
                  }
              },
              sort: sorter 
            });
    },

    addTracks: function( tracks, inStartup ) {
        this.pane = this;
        var thisB = this;
       
        array.forEach( tracks, function( track ) {
            var trackConf = track.conf || track;

            var categoryFacet = this.get('categoryFacet');
            var categoryNames = (
                trackConf.metadata && trackConf.metadata[ categoryFacet ]
                    || trackConf[ categoryFacet ]
                    || track[ categoryFacet ]
                    || 'Uncategorized'
            ).split(/\s*\/\s*/);
{'fraction_non_alphanumeric': 0.1142010485525416, 'fraction_numerical': 0.0018235696375655346, 'mean_word_length': 1.3975409836065573, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 8, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4812395', 'n_tokens_mistral': 2419, 'n_tokens_neox': 2308, 'n_words': 426}