<commit_before>import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';

export default class GhExploreIframe extends Component {
    @service explore;
    @service router;
    @service feature;

    @action
    setup() {
        this.explore.getExploreIframe().src = this.explore.getIframeURL();

        window.addEventListener('message', async (event) => {
            // only process messages coming from the explore iframe
            if (event?.data && this.explore.getIframeURL().includes(event?.origin)) {
                if (event.data?.request === 'apiUrl') {
                    this._handleUrlRequest();
                }

                if (event.data?.route) {
                    this._handleRouteUpdate(event.data);
                }

                if (event.data?.siteData) {
                    this._handleSiteDataUpdate(event.data);
                }
            }
        });
    }

    // The iframe can send route updates to navigate to within Admin, as some routes
    // have to be rendered within the iframe and others require to break out of it.
    _handleRouteUpdate(data) {
        const route = data.route;
        this.explore.isIframeTransition = route?.includes('/explore');
        this.explore.toggleExploreWindow(this.explore.isIframeTransition);
        this.router.transitionTo(route);
    }

    _handleUrlRequest() {
        this.explore.getExploreIframe().contentWindow.postMessage({
            request: 'apiUrl',
            response: {apiUrl: this.explore.apiUrl, darkMode: this.feature.nightShift}
        }, '*');
    }

    _handleSiteDataUpdate(data) {
        this.explore.siteData = data?.siteData ?? {};
    }
}
<commit_msg>Fixed `<GhExploreIframe>` leaking event listeners and throwing errors in tests<commit_after>import Component from '@glimmer/component';
import {action} from '@ember/object';
import {inject as service} from '@ember/service';

export default class GhExploreIframe extends Component {
    @service explore;
    @service router;
    @service feature;

    willDestroy() {
        super.willDestroy(...arguments);
        window.removeEventListener('message', this.handleIframeMessage);
    }

    @action
    setup() {
        this.explore.getExploreIframe().src = this.explore.getIframeURL();
        window.addEventListener('message', this.handleIframeMessage);
    }

    @action
    async handleIframeMessage(event) {
        if (this.isDestroyed || this.isDestroying) {
            return;
        }

        // only process messages coming from the explore iframe
        if (event?.data && this.explore.getIframeURL().includes(event?.origin)) {
            if (event.data?.request === 'apiUrl') {
                this._handleUrlRequest();
            }

            if (event.data?.route) {
                this._handleRouteUpdate(event.data);
            }

            if (event.data?.siteData) {
                this._handleSiteDataUpdate(event.data);
            }
        }
    }

    // The iframe can send route updates to navigate to within Admin, as some routes
    // have to be rendered within the iframe and others require to break out of it.
    _handleRouteUpdate(data) {
        const route = data.route;
        this.explore.isIframeTransition = route?.includes('/explore');
        this.explore.toggleExploreWindow(this.explore.isIframeTransition);
        this.router.transitionTo(route);
    }

    _handleUrlRequest() {
        this.explore.getExploreIframe().contentWindow.postMessage({
            request: 'apiUrl',
            response: {apiUrl: this.explore.apiUrl, darkMode: this.feature.nightShift}
        }, '*');
    }

    _handleSiteDataUpdate(data) {
        this.explore.siteData = data?.siteData ?? {};
    }
}

{'fraction_non_alphanumeric': 0.11412043123849593, 'fraction_numerical': 0.0, 'mean_word_length': 2.3222707423580786, 'pattern_counts': {'":': 0, '<': 4, '<?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': '5443241', 'n_tokens_mistral': 1063, 'n_tokens_neox': 1016, 'n_words': 225}