<commit_before>// **Extends** Backbone.View
//
// **Jurisdiction** .main-content
//
// **Usage** ```require(['reg-view'], function(RegView) {})```
define('reg-view', ['jquery', 'underscore', 'backbone', 'jquery-scrollstop', 'dispatch', 'definition-view', 'sub-head-view', 'reg-model', 'section-footer-view', 'regs-router'], function($, _, Backbone, jQScroll, Dispatch, DefinitionView, SubHeadView, RegModel, SectionFooterView, Router) {
    'use strict';

    var RegView = Backbone.View.extend({
        events: {
            'click .definition': 'termLinkHandler',
            'click .inline-interp-header': 'expandInterp',
            'mouseenter *[data-permalink-section]': 'showPermalink',
            'click .permalink-marker': 'permalinkMarkerHandler',
            'click .definition.active': 'openDefinitionLinkHandler'
        },

        initialize: function() {
            // **Event Listeners**
            //
            // * when a definition is removed, update term links
            Dispatch.on('definition:remove', this.closeDefinition, this);
            Dispatch.on('toc:click', this.loadSection, this);
            Dispatch.on('openSection:set', this.loadSection, this);

            Dispatch.on('breakaway:open', this.hideContent, this);
            Dispatch.on('breakaway:close', this.showContent, this);

            // * when a scroll event completes, check what the active secion is
            $(window).on('scrollstop', (_.bind(this.checkActiveSection, this)));

            // set active section vars
            // @TODO: how do activeSection and Dispatch.get('section') live together?
            this.activeSection = '';
            this.$activeSection = '';
            this.$sections = {};

            this.updateWayfinding();

            // this might be silly?
            this.$window = $(window);

            // new View instance for subheader
            this.header = new SubHeadView();
            Dispatch.set('sectionNav', new SectionFooterView({el: this.$el.find('.section-nav')}));

        },

        // naive way to update the active table of contents link and wayfinding header
        // once a scroll event ends, we loop through each content section DOM node
        // the first one whose offset is greater than the window scroll position, accounting
        // for the fixed position header, is deemed the active section
        checkActiveSection: function() {
            var len = this.$contentContainer.length - 1;

            for (var i = 0; i <= len; i++) {
                if (this.$sections[i].offset().top + this.$contentHeader.height() >= this.$window.scrollTop()) {
                    if (_.isEmpty(this.activeSection) || (this.activeSection !== this.$sections[i].id)) {
                        this.activeSection = this.$sections[i][0].id;
                        this.$activeSection = this.$sections[i][0];
                        // **Event** trigger active section change
                        Dispatch.trigger('activeSection:change', this.activeSection);
                        return;
                    }
                }
            }
                 
            return this;
        },

        // ask for section data, when promise is completed,
        // re-render view
        loadSection: function(sectionId) {
            var returned = RegModel.get(sectionId);

            // visually indicate that a new section is loading
            $('.main-content').addClass('loading');

            if (typeof returned.done !== 'undefined') {
                // @TODO: error handling
                returned.done(function(section) {
                    this.openSection(section, sectionId);
                }.bind(this));
            }
            else {
               this.openSection(returned, sectionId); 
            }
        },

        openSection: function(section, sectionId) {
            Dispatch.set('section', sectionId);
            this.$el.html(section);
            Dispatch.trigger('mainContent:change', this.$el, 'reg-text');

            window.scrollTo(0, 0);
            Dispatch.trigger('section:open', sectionId);

            Dispatch.set('sectionNav', new SectionFooterView({el: this.$el.find('.section-nav')}));
            Router.navigate('regulation/' + sectionId + '/' + Dispatch.getVersion());

            $('.main-content').removeClass('loading');

            this.updateWayfinding();
        },

        updateWayfinding: function() {
            var i, len;

            // cache all sections in the DOM eligible to be the active section
            // also cache some jQobjs that we will refer to frequently
            this.$contentHeader = this.$contentHeader || $('header.reg-header');

            // sections that are eligible for being the active section
            this.$contentContainer = this.$el.find('.level-1 li[id], .reg-section, .appendix-section, .supplement-section');

            // cache jQobjs of each reg section
            len = this.$contentContainer.length;
            for (i = 0; i < len; i++) {
                this.$sections[i] = $(this.$contentContainer[i]);
            }
        },

        // for a consistent API
        render: function() {
            this.loadSection(Dispatch.getOpenSection());
        },

        // only concerned with resetting DOM, no matter
        // what way the definition was closed
        closeDefinition: function() {
            this.clearActiveTerms();
        },

        // only concerned with sending GA event if the definition
        // is closed via active term link
        openDefinitionLinkHandler: function(e) {
            Dispatch.trigger('ga-event:definition', {
                action: 'clicked key term to close definition',
                context: $(e.target).data('definition')
            });
        },

        toggleDefinition: function($link) {
            this.setActiveTerm($link); 

            return this;
        },

        // content section key term link click handler
        termLinkHandler: function(e) {
            e.preventDefault();

            var $link = $(e.target),
                defId = $link.attr('data-definition');

            // if this link is already active, toggle def shut
            if ($link.data('active')) {
                Dispatch.remove('definition');
                this.clearActiveTerms();
            }
            else {
                // if its the same definition, diff term link
                if (Dispatch.getViewId('definition') === defId) {
                    this.toggleDefinition($link);
                }
                else {
                    // close old definition, if there is one
                    Dispatch.remove('definition');
                    // open new definition
                    this.openDefinition(defId, $link);
                }
            }

            return this;
        },

        openDefinition: function(defId, $link) {
            var definition = new DefinitionView({
                id: defId,
                $anchor: $link
            });

            Dispatch.set('definition', definition);
            Dispatch.trigger('definition:open');
            Dispatch.trigger('ga-event:definition', {
                action: 'clicked key term to open definition',
                context: defId
            });
            this.setActiveTerm($link);

            return definition;
        },

        // handler for when inline interpretation is clicked
        expandInterp: function(e) {

            // user can click anywhere in the header of a closed interp
            // for an open interp, they can click "hide" button or header
            e.stopPropagation();
            var header = $(e.currentTarget),
                section = header.parent(),
                button = header.find('.expand-button');

            section.toggleClass('open');
            header.next('.hidden').slideToggle();
            button.toggleClass('open').html(section.hasClass('open') ? 'Hide' : 'Show');

            return this;
        },

        // handler for when a permalink icon should be shown
        showPermalink: function(e) {
            $('.permalink-marker').remove();

            var permalink = document.createElement('a'),
                $section = $(e.currentTarget),
                $permalink;

            permalink.href = '#' + $section[0].id;
            permalink.innerHTML = 'Permalink';
            permalink.className = 'permalink-marker';
            $permalink = $(permalink);

            $section.children().first().prepend($permalink);
        },

        // send GA event when permalink is clicked
        permalinkMarkerHandler: function(e) {
            Dispatch.trigger('ga-event:permalink', $(e.target).attr('href'));
        },

        changeFocus: function(id) {
            $(id).focus();
        },

        // Sets DOM back to neutral state
        clearActiveTerms: function() {
            this.$el.find('.active.definition')
                .removeClass('active')
                .removeData('active');
        },

        setActiveTerm: function($link) {
            this.clearActiveTerms();
            $link.addClass('active').data('active', 1);
        },

        remove: function() {
            this.stopListening();
            return this;
        },

        hideContent: function() {
            this.$el.fadeOut(1000);
        },

        showContent: function() {
            this.$el.fadeIn();
        }
    });

    return RegView;
});
<commit_msg>fixing inline interp expansion<commit_after>// **Extends** Backbone.View
//
// **Jurisdiction** .main-content
//
// **Usage** ```require(['reg-view'], function(RegView) {})```
define('reg-view', ['jquery', 'underscore', 'backbone', 'jquery-scrollstop', 'dispatch', 'definition-view', 'sub-head-view', 'reg-model', 'section-footer-view', 'regs-router'], function($, _, Backbone, jQScroll, Dispatch, DefinitionView, SubHeadView, RegModel, SectionFooterView, Router) {
    'use strict';

    var RegView = Backbone.View.extend({
        el: '#content-wrapper',

        events: {
            'click .definition': 'termLinkHandler',
            'click .inline-interp-header': 'expandInterp',
            'mouseenter *[data-permalink-section]': 'showPermalink',
            'click .permalink-marker': 'permalinkMarkerHandler',
            'click .definition.active': 'openDefinitionLinkHandler'
        },

        initialize: function() {
            // **Event Listeners**
            //
            // * when a definition is removed, update term links
            Dispatch.on('definition:remove', this.closeDefinition, this);
            Dispatch.on('toc:click', this.loadSection, this);
            Dispatch.on('openSection:set', this.loadSection, this);

            Dispatch.on('breakaway:open', this.hideContent, this);
            Dispatch.on('breakaway:close', this.showContent, this);

            // * when a scroll event completes, check what the active secion is
            $(window).on('scrollstop', (_.bind(this.checkActiveSection, this)));

            // set active section vars
            // @TODO: how do activeSection and Dispatch.get('section') live together?
            this.activeSection = '';
            this.$activeSection = '';
            this.$sections = {};

            this.updateWayfinding();

            // this might be silly?
            this.$window = $(window);

            // new View instance for subheader
            this.header = new SubHeadView();
            Dispatch.set('sectionNav', new SectionFooterView({el: this.$el.find('.section-nav')}));

        },

        // naive way to update the active table of contents link and wayfinding header
        // once a scroll event ends, we loop through each content section DOM node
        // the first one whose offset is greater than the window scroll position, accounting
        // for the fixed position header, is deemed the active section
        checkActiveSection: function() {
            var len = this.$contentContainer.length - 1;

            for (var i = 0; i <= len; i++) {
                if (this.$sections[i].offset().top + this.$contentHeader.height() >= this.$window.scrollTop()) {
                    if (_.isEmpty(this.activeSection) || (this.activeSection !== this.$sections[i].id)) {
                        this.activeSection = this.$sections[i][0].id;
                        this.$activeSection = this.$sections[i][0];
                        // **Event** trigger active section change
                        Dispatch.trigger('activeSection:change', this.activeSection);
                        return;
                    }
                }
            }
                 
            return this;
        },

        // ask for section data, when promise is completed,
        // re-render view
        loadSection: function(sectionId) {
            var returned = RegModel.get(sectionId);

            // visually indicate that a new section is loading
            $('.main-content').addClass('loading');

            if (typeof returned.done !== 'undefined') {
                // @TODO: error handling
                returned.done(function(section) {
                    this.openSection(section, sectionId);
                }.bind(this));
            }
            else {
               this.openSection(returned, sectionId); 
            }
        },

        openSection: function(section, sectionId) {
            Dispatch.set('section', sectionId);
            this.$el.html(section);
            Dispatch.trigger('mainContent:change', this.$el, 'reg-text');

            window.scrollTo(0, 0);
            Dispatch.trigger('section:open', sectionId);

            Dispatch.set('sectionNav', new SectionFooterView({el: this.$el.find('.section-nav')}));
            Router.navigate('regulation/' + sectionId + '/' + Dispatch.getVersion());

            $('.main-content').removeClass('loading');

            this.updateWayfinding();
        },

        updateWayfinding: function() {
            var i, len;

            // cache all sections in the DOM eligible to be the active section
            // also cache some jQobjs that we will refer to frequently
            this.$contentHeader = this.$contentHeader || $('header.reg-header');

            // sections that are eligible for being the active section
            this.$contentContainer = this.$el.find('.level-1 li[id], .reg-section, .appendix-section, .supplement-section');

            // cache jQobjs of each reg section
            len = this.$contentContainer.length;
            for (i = 0; i < len; i++) {
                this.$sections[i] = $(this.$contentContainer[i]);
            }
        },

        // for a consistent API
        render: function() {
            this.loadSection(Dispatch.getOpenSection());
        },

        // only concerned with resetting DOM, no matter
        // what way the definition was closed
        closeDefinition: function() {
            this.clearActiveTerms();
        },

        // only concerned with sending GA event if the definition
        // is closed via active term link
        openDefinitionLinkHandler: function(e) {
            Dispatch.trigger('ga-event:definition', {
                action: 'clicked key term to close definition',
                context: $(e.target).data('definition')
            });
        },

        toggleDefinition: function($link) {
            this.setActiveTerm($link); 

            return this;
        },

        // content section key term link click handler
        termLinkHandler: function(e) {
            e.preventDefault();

            var $link = $(e.target),
                defId = $link.attr('data-definition');

            // if this link is already active, toggle def shut
            if ($link.data('active')) {
                Dispatch.remove('definition');
                this.clearActiveTerms();
            }
            else {
                // if its the same definition, diff term link
                if (Dispatch.getViewId('definition') === defId) {
                    this.toggleDefinition($link);
                }
                else {
                    // close old definition, if there is one
                    Dispatch.remove('definition');
                    // open new definition
                    this.openDefinition(defId, $link);
                }
            }

            return this;
        },

        openDefinition: function(defId, $link) {
            var definition = new DefinitionView({
                id: defId,
                $anchor: $link
            });

            Dispatch.set('definition', definition);
            Dispatch.trigger('definition:open');
            Dispatch.trigger('ga-event:definition', {
                action: 'clicked key term to open definition',
                context: defId
            });
            this.setActiveTerm($link);

            return definition;
        },

        // handler for when inline interpretation is clicked
        expandInterp: function(e) {
            // user can click anywhere in the header of a closed interp
            // for an open interp, they can click "hide" button or header
            e.stopPropagation();
            var header = $(e.currentTarget),
                section = header.parent(),
                button = header.find('.expand-button');

            section.toggleClass('open');
            header.next('.hidden').slideToggle();
            button.toggleClass('open').html(section.hasClass('open') ? 'Hide' : 'Show');

            return this;
        },

        // handler for when a permalink icon should be shown
        showPermalink: function(e) {
            $('.permalink-marker').remove();

            var permalink = document.createElement('a'),
                $section = $(e.currentTarget),
                $permalink;

            permalink.href = '#' + $section[0].id;
            permalink.innerHTML = 'Permalink';
            permalink.className = 'permalink-marker';
            $permalink = $(permalink);

            $section.children().first().prepend($permalink);
        },

        // send GA event when permalink is clicked
        permalinkMarkerHandler: function(e) {
            Dispatch.trigger('ga-event:permalink', $(e.target).attr('href'));
        },

        changeFocus: function(id) {
            $(id).focus();
        },

        // Sets DOM back to neutral state
        clearActiveTerms: function() {
            this.$el.find('.active.definition')
                .removeClass('active')
                .removeData('active');
        },

        setActiveTerm: function($link) {
            this.clearActiveTerms();
            $link.addClass('active').data('active', 1);
        },

        remove: function() {
            this.stopListening();
            return this;
        },

        hideContent: function() {
            this.$el.fadeOut(1000);
        },

        showContent: function() {
            this.$el.fadeIn();
        }
    });

    return RegView;
});

{'fraction_non_alphanumeric': 0.12591078261781202, 'fraction_numerical': 0.0014677360171934791, 'mean_word_length': 1.711869225302061, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2405188', 'n_tokens_mistral': 4831, 'n_tokens_neox': 4560, 'n_words': 1173}