<commit_before>import DiffMatchPatch from 'diff-match-patch';
import shortid from 'shortid';

class LinkFunction {
    constructor(compareVersions, lock, $timeout, scope, elem) {
        this.compareVersions = compareVersions;
        this.lock = lock;
        this.$timeout = $timeout;
        this.scope = scope;
        this.elem = elem;

        this.diffMatchPatch = new DiffMatchPatch();

        this.init();
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#init
     * @private
     * @description Initializes the directive with default values for the scope
     * and with necessary watchers.
     */
    init() {
        this.scope.$watch('[article, compareWith]', (newVal, oldVal) => {
            if (newVal && newVal !== oldVal) {
                this.openItem();
            }
        });

        this.scope.remove = this.remove.bind(this);

        this.openItem();
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#remove
     * @description Removes the item from opened board.
     */
    remove(item) {
        this.compareVersions.remove({id: item._id, version: item._current_version});
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#openItem
     * @private
     * @description Opens the selected article version in sdArticleEdit directive.
     */
    openItem() {
        let item = _.find(this.compareVersions.versions, {_current_version: this.scope.article.version});

        this.scope.origItem = item;
        this.scope.item = _.cloneDeep(item);
        this.scope.compareView = true;
        this.scope._editable = false;
        this.scope.isMediaType = _.includes(['audio', 'video', 'picture', 'graphic'], this.scope.item.type);

        if (this.scope.compareWith && this.scope.article !== this.scope.compareWith) {
            let compareWithItem = _.find(this.compareVersions.versions,
                {_current_version: this.scope.compareWith.version});

            this.scope.compareWithItem = _.create(compareWithItem);
            this.setVersionsDifference(this.scope.item, this.scope.compareWithItem);
        }

        if (this.scope.focus) {
            this.$timeout(() => {
                this.elem.children().focus();
            }, 0, false);
        }

        this.scope.isLocked = this.lock.isLocked(item);
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#setVersionsDifference
     * @param {Object} item - current item version
     * @param {Object} oldItem - old item to compare with
     * @description Changes 'headline', 'abstract', 'body_footer', 'body_html', 'byline' from item
     * in order to highlight the differences from oldItem
     */
    setVersionsDifference(item, oldItem) {
        const fields = ['headline', 'abstract', 'body_footer', 'body_html', 'byline'];

        _.map(fields, (field) => {
            if (item[field] || oldItem[field]) {
                item[field] = this.highlightDifferences(item[field], oldItem[field]);
            }
        });

        if (item.associations && item.associations.featuremedia &&
            oldItem.associations && oldItem.associations.featuremedia) {
            item.associations.featuremedia.description_text = this.highlightDifferences(
                item.associations.featuremedia.description_text,
                oldItem.associations.featuremedia.description_text
            );
        }
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#highlightDifferences
     * @param {String} newText - current text
     * @param {String} oldText - old text to compare with
     * @description Highlight the differences between new text and old text
     */
    highlightDifferences(newText, oldText) {
        let mapWords = {};
        let pOldText = this.extractHtml(oldText, mapWords);
        let pNewText = this.extractHtml(newText, mapWords);
        let diffs = this.diffMatchPatch.diff_main(pOldText, pNewText);

        this.diffMatchPatch.diff_cleanupSemantic(diffs);
        diffs = this.splitByTranslationOfTags(diffs, this.reverseMap(mapWords, false));

        let text = this.diffMatchPatch
            .diff_prettyHtml(diffs);

        text = this.replaceWords(text, this.reverseMap(mapWords, true));
        return text;
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#extractHtml
     * @param {String} text - html text
     * @param {Map} mapWords - translation for words
     * @description Replace all html tags with custom tags.
     */
    extractHtml(text, mapWords) {
        let tags = (text || '').match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g);

        _.map(tags, (tag) => {
            if (!mapWords[tag]) {
                mapWords[tag] = shortid.generate();
            }
        });

        return this.replaceWords(text, mapWords);
    }

    /**
     * @ngdoc replaceWords
     * @name sdCompareVersionsArticle#replaceWords
     * @param {String} text - text
     * @param {Map} mapWords - translation for words
     * @description Replace in text the words from mapWords with corespondent translation
     */
    replaceWords(text, mapWords) {
        let result = text;

        result = result.replace(/\n/g, '');

        _.map(Object.keys(mapWords), (key) => {
            result = result.replace(
                new RegExp(key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'),<commit_msg>fix(compare): Fixed issue with undefined text in replace function<commit_after>import DiffMatchPatch from 'diff-match-patch';
import shortid from 'shortid';

class LinkFunction {
    constructor(compareVersions, lock, $timeout, scope, elem) {
        this.compareVersions = compareVersions;
        this.lock = lock;
        this.$timeout = $timeout;
        this.scope = scope;
        this.elem = elem;

        this.diffMatchPatch = new DiffMatchPatch();

        this.init();
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#init
     * @private
     * @description Initializes the directive with default values for the scope
     * and with necessary watchers.
     */
    init() {
        this.scope.$watch('[article, compareWith]', (newVal, oldVal) => {
            if (newVal && newVal !== oldVal) {
                this.openItem();
            }
        });

        this.scope.remove = this.remove.bind(this);

        this.openItem();
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#remove
     * @description Removes the item from opened board.
     */
    remove(item) {
        this.compareVersions.remove({id: item._id, version: item._current_version});
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#openItem
     * @private
     * @description Opens the selected article version in sdArticleEdit directive.
     */
    openItem() {
        let item = _.find(this.compareVersions.versions, {_current_version: this.scope.article.version});

        this.scope.origItem = item;
        this.scope.item = _.cloneDeep(item);
        this.scope.compareView = true;
        this.scope._editable = false;
        this.scope.isMediaType = _.includes(['audio', 'video', 'picture', 'graphic'], this.scope.item.type);

        if (this.scope.compareWith && this.scope.article !== this.scope.compareWith) {
            let compareWithItem = _.find(this.compareVersions.versions,
                {_current_version: this.scope.compareWith.version});

            this.scope.compareWithItem = _.create(compareWithItem);
            this.setVersionsDifference(this.scope.item, this.scope.compareWithItem);
        }

        if (this.scope.focus) {
            this.$timeout(() => {
                this.elem.children().focus();
            }, 0, false);
        }

        this.scope.isLocked = this.lock.isLocked(item);
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#setVersionsDifference
     * @param {Object} item - current item version
     * @param {Object} oldItem - old item to compare with
     * @description Changes 'headline', 'abstract', 'body_footer', 'body_html', 'byline' from item
     * in order to highlight the differences from oldItem
     */
    setVersionsDifference(item, oldItem) {
        const fields = ['headline', 'abstract', 'body_footer', 'body_html', 'byline'];

        _.map(fields, (field) => {
            if (item[field] || oldItem[field]) {
                item[field] = this.highlightDifferences(item[field], oldItem[field]);
            }
        });

        if (item.associations && item.associations.featuremedia &&
            oldItem.associations && oldItem.associations.featuremedia) {
            item.associations.featuremedia.description_text = this.highlightDifferences(
                item.associations.featuremedia.description_text,
                oldItem.associations.featuremedia.description_text
            );
        }
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#highlightDifferences
     * @param {String} newText - current text
     * @param {String} oldText - old text to compare with
     * @description Highlight the differences between new text and old text
     */
    highlightDifferences(newText, oldText) {
        let mapWords = {};
        let pOldText = this.extractHtml(oldText, mapWords);
        let pNewText = this.extractHtml(newText, mapWords);
        let diffs = this.diffMatchPatch.diff_main(pOldText, pNewText);

        this.diffMatchPatch.diff_cleanupSemantic(diffs);
        diffs = this.splitByTranslationOfTags(diffs, this.reverseMap(mapWords, false));

        let text = this.diffMatchPatch
            .diff_prettyHtml(diffs);

        text = this.replaceWords(text, this.reverseMap(mapWords, true));
        return text;
    }

    /**
     * @ngdoc method
     * @name sdCompareVersionsArticle#extractHtml
     * @param {String} text - html text
     * @param {Map} mapWords - translation for words
     * @description Replace all html tags with custom tags.
     */
    extractHtml(text, mapWords) {
        let tags = (text || '').match(/<(?:"[^"]*"['"]*|'[^']*'['"]*|[^'">])+>/g);

        _.map(tags, (tag) => {
            if (!mapWords[tag]) {
                mapWords[tag] = shortid.generate();
            }
        });

        return this.replaceWords(text, mapWords);
    }

    /**
     * @ngdoc replaceWords
     * @name sdCompareVersionsArticle#replaceWords
     * @param {String} text - text
     * @param {Map} mapWords - translation for words
     * @description Replace in text the words from mapWords with corespondent translation
     */
    replaceWords(text, mapWords) {
        let result = text || '';

        result = result.replace(/\n/g, '');

        _.map(Object.keys(mapWords), (key) => {
            result = result.replace(
                new RegExp(key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'g'),
{'fraction_non_alphanumeric': 0.12969440353460973, 'fraction_numerical': 0.0001840942562592047, 'mean_word_length': 2.3752718235476857, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 17, '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': '5715151', 'n_tokens_mistral': 3204, 'n_tokens_neox': 3054, 'n_words': 663}