<commit_before>define(function (require, exports, module) {
'use strict';

var Decorator = require("wed/decorator").Decorator;
var oop = require("wed/oop");
var $ = require("jquery");
var util = require("wed/util");
var jqutil = require("wed/jqutil");

/**
 * @param {Mode} mode The mode object.
 * @param {Listener} listener The DOM listener that will listen to
 * changes on the document.
 * @param {Editor} editor The Wed editor to which the mode is applied.
 */
function GenericDecorator(mode, meta) {
    // Pass the rest of arguments to super's constructor.
    Decorator.apply(this, Array.prototype.slice.call(arguments, 2));

    this._mode = mode;
    this._meta = meta;

    this._domlistener.addHandler(
        "included-element",
        util.classFromOriginalName("*"),
        function ($root, $tree, $parent,
                  $prev, $next, $el) {
            this.elementDecorator(
                $root, $el,
                util.eventHandler(this._contextMenuHandler.bind(this)));
        }.bind(this));

    this._domlistener.addHandler(
        "included-element",
        util.classFromOriginalName("*"),
        function ($root, $tree, $parent, $prev, $next, $el) {
            // Skip elements which would already have been removed from
            // the tree. Unlikely but...
            if ($el.closest($root).length === 0)
                return;

            var klass = this._meta.getAdditionalClasses($el.get(0));
            if (klass.length > 0)
                $el.addClass(klass);
        }.bind(this));

    this._domlistener.addHandler(
        "children-changed",
        util.classFromOriginalName("*"),
        function ($root, $added, $removed, $previous_sibling, $next_sibling, $element) {
            if ($added.is("._real, ._phantom_wrap") ||
                $removed.is("._real, ._phantom_wrap") ||
                $added.filter(jqutil.textFilter).length +
                $removed.filter(jqutil.textFilter).length > 0)
                this.elementDecorator(
                    $root, $element,
                    util.eventHandler(this._contextMenuHandler.bind(this)));
        }.bind(this));

    this._domlistener.addHandler(
        "text-changed",
        util.classFromOriginalName("*"),
        function ($root, $element) {
            this.elementDecorator(
                $root, $element.parent(),
                util.eventHandler(this._contextMenuHandler.bind(this)));
        }.bind(this));

}

oop.inherit(GenericDecorator, Decorator);

(function () {
    this._contextMenuHandler = function (ev, jQthis) {
        var node = $(jQthis).parents('._real').first().get(0);
        var menu_items = [];
        if (node.parentNode !== this._editor.root) {
            var orig = util.getOriginalName(node);
            var trs = this._editor.tr.getTagTransformations(
                ["unwrap", "delete-element"], orig);
            if (trs !== undefined) {
                trs.forEach(function (tr) {
                    var $a = $("<a tabindex='-1' href='#'>" +
                               tr.getDescriptionFor(orig) + "</a>");
                    $a.click({'tr': tr, 'node': node,
                              'element_name': orig },
                             this._editor._fireTransformation.bind(this._editor));
                    menu_items.push($("<li>").append($a).get(0));
                }.bind(this));
            }

            // Get the events that can happen before this node.
            var parent = node.parentNode;
            var index = Array.prototype.indexOf.call(parent.childNodes, node);
            var tree_caret = this._editor.toTreeCaret(parent, index);
            this._editor.validator.possibleAt(
                tree_caret[0],
                tree_caret[1]).forEach(function (ev) {
                    if (ev.params[0] !== "enterStartTag")
                        return;

                    var unresolved = this._editor.resolver.unresolveName(
                        ev.params[1], ev.params[2]);

                    var trs = this._editor.tr.getTagTransformations(
                        "insert", unresolved);
                    if (trs === undefined)
                        return;

                    for(var tr_ix = 0, tr; (tr = trs[tr_ix]) !== undefined;
                        ++tr_ix) {
                        var $a = $("<a tabindex='0' href='#'>" +
                                   tr.getDescriptionFor(unresolved) +
                                   "</a>");
                        $a.click({'tr': tr,
                                  'element_name': unresolved },
                                 function (e) {
                                     this._editor.dismissContextMenu();
                                     this._editor.setTreeCaret(tree_caret);
                                     this._editor._fireTransformation(e);<commit_msg>Added support for context menus at end tag label.<commit_after>define(function (require, exports, module) {
'use strict';

var Decorator = require("wed/decorator").Decorator;
var oop = require("wed/oop");
var $ = require("jquery");
var util = require("wed/util");
var jqutil = require("wed/jqutil");

/**
 * @param {Mode} mode The mode object.
 * @param {Listener} listener The DOM listener that will listen to
 * changes on the document.
 * @param {Editor} editor The Wed editor to which the mode is applied.
 */
function GenericDecorator(mode, meta) {
    // Pass the rest of arguments to super's constructor.
    Decorator.apply(this, Array.prototype.slice.call(arguments, 2));

    this._mode = mode;
    this._meta = meta;

    this._domlistener.addHandler(
        "included-element",
        util.classFromOriginalName("*"),
        function ($root, $tree, $parent,
                  $prev, $next, $el) {
            this.elementDecorator(
                $root, $el,
                util.eventHandler(this._contextMenuHandler.bind(this, true)),
                util.eventHandler(this._contextMenuHandler.bind(this, false)));
        }.bind(this));

    this._domlistener.addHandler(
        "included-element",
        util.classFromOriginalName("*"),
        function ($root, $tree, $parent, $prev, $next, $el) {
            // Skip elements which would already have been removed from
            // the tree. Unlikely but...
            if ($el.closest($root).length === 0)
                return;

            var klass = this._meta.getAdditionalClasses($el.get(0));
            if (klass.length > 0)
                $el.addClass(klass);
        }.bind(this));

    this._domlistener.addHandler(
        "children-changed",
        util.classFromOriginalName("*"),
        function ($root, $added, $removed, $previous_sibling, $next_sibling, $element) {
            if ($added.is("._real, ._phantom_wrap") ||
                $removed.is("._real, ._phantom_wrap") ||
                $added.filter(jqutil.textFilter).length +
                $removed.filter(jqutil.textFilter).length > 0)
                this.elementDecorator(
                    $root, $element,
                    util.eventHandler(this._contextMenuHandler.bind(this,
                                                                    true)),
                    util.eventHandler(this._contextMenuHandler.bind(this,
                                                                    false)));
        }.bind(this));

    this._domlistener.addHandler(
        "text-changed",
        util.classFromOriginalName("*"),
        function ($root, $element) {
            this.elementDecorator(
                $root, $element.parent(),
                util.eventHandler(this._contextMenuHandlerAtStart.bind(this)),
                util.eventHandler(this._contextMenuHandlerAtEnd.bind(this)));
        }.bind(this));

}

oop.inherit(GenericDecorator, Decorator);

(function () {
    this._contextMenuHandler = function (at_start, ev, jQthis) {
        var node = $(jQthis).parents('._real').first().get(0);
        var menu_items = [];
        if (node.parentNode !== this._editor.root) {
            var orig = util.getOriginalName(node);
            var trs = this._editor.tr.getTagTransformations(
                ["unwrap", "delete-element"], orig);
            if (trs !== undefined) {
                trs.forEach(function (tr) {
                    var $a = $("<a tabindex='-1' href='#'>" +
                               tr.getDescriptionFor(orig) + "</a>");
                    $a.click({'tr': tr, 'node': node,
                              'element_name': orig },
                             this._editor._fireTransformation.bind(this._editor));
                    menu_items.push($("<li>").append($a).get(0));
                }.bind(this));
            }

            var parent = node.parentNode;
            var index = Array.prototype.indexOf.call(parent.childNodes, node);

            // If we're on the end label, we want the events *after* the node.
            if (!at_start)
                index++;

            var tree_caret = this._editor.toTreeCaret(parent, index);
            this._editor.validator.possibleAt(
                tree_caret[0],
                tree_caret[1]).forEach(function (ev) {
                    if (ev.params[0] !== "enterStartTag")
                        return;

                    var unresolved = this._editor.resolver.unresolveName(
                        ev.params[1], ev.params[2]);

                    var trs = this._editor.tr.getTagTransformations(
                        "insert", unresolved);
                    if (trs === undefined)
                        return;

                    for(var tr_ix = 0, tr; (tr = trs[tr_ix]) !== undefined;
                        ++tr_ix) {
                        var $a = $("<a tabindex='0' href='#'>" +
                                   tr.getDescriptionFor(unresolved) +
                                   "</a>");
                        $a.click({'tr': tr,
                                  'element_name': unresolved },
                                 function (e) {
                                     this._editor.dismissContextMenu();
                                     this._editor.setTreeCaret(tree_caret);
                                     this._editor._fireTransformation(e);
{'fraction_non_alphanumeric': 0.13188957174909766, 'fraction_numerical': 0.0029265437518290896, 'mean_word_length': 1.5993914807302232, 'pattern_counts': {'":': 0, '<': 13, '<?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': 18, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4880777', 'n_tokens_mistral': 2788, 'n_tokens_neox': 2659, 'n_words': 552}