<commit_before> /**
  * @module decorator
  * @desc Basic decoration facilities.
  * @author <NAME>
  * @license MPL 2.0
  * @copyright 2013, 2014 Mangalam Research Center for Buddhist Languages
  */
define(/** @lends module:decorator */ function (require, exports, module) {
'use strict';

var util = require("./util");
var $ = require("jquery");
var domutil = require("./domutil");
var jqutil = require("./jqutil");
var transformation = require("./transformation");
var tooltip = require("./gui/tooltip").tooltip;

/**
 * @classdesc A decorator is responsible for adding decorations to a
 * tree of DOM elements. Decorations are GUI elements.
 *
 * @constructor
 * @param {module:domlistener~Listener} domlistener The listener that
 * the decorator must use to know when the DOM tree has changed and
 * must be redecorated.
 * @param {module:wed~Editor} editor The editor instance for which
 * this decorator was created.
 * @param {module:gui_updater~GUIUpdater} gui_updater The updater to
 * use to modify the GUI tree. All modifications to the GUI must go
 * through this updater.
*/
function Decorator(domlistener, editor, gui_updater) {
    this._domlistener = domlistener;
    this._editor = editor;
    this._gui_updater = gui_updater;
}

exports.Decorator = Decorator;

/**
 * Request that the decorator add its event handlers to its listener.
 */
Decorator.prototype.addHandlers = function () {
    this._domlistener.addHandler(
        "added-element",
        "._real, ._phantom, ._phantom_wrap",
        this.contentEditableHandler.bind(this));
};

/**
 * Start listening to changes to the DOM tree.
 *
 * @param {jQuery} $root The DOM root that this decorator listens
 * to. This must be the same root as the root that the this
 * decorator's domlistener listens on and the same root as the root
 * which the GUI updater updates.
 */
Decorator.prototype.startListening = function ($root) {
    var $contents = $root.contents();
    $contents.detach();
    this._domlistener.startListening();
    this._gui_updater.insertAt($root[0], 0, $contents.toArray());
};

/**
 * This function adds a separator between each child element of the
 * element passed as <code>el</code>. The function only considers
 * "._real" elements.
 *
 * @param {Node} el The element to decorate.
 * @param {string|jQuery} sep A separator.
 */
Decorator.prototype.listDecorator = function (el, sep) {
    // We expect to work with a homogeneous list. That is, all
    // children the same element.
    var name_map = {};
    $(el).children('._real').each(function () {
        name_map[util.getOriginalName(this)] = 1;
    });

    var tags = Object.keys(name_map);
    if (tags.length > 1)
        throw new Error("calling listDecorator on a non-homogeneous list.");

    if (tags.length === 0)
        return; // Nothing to work with

    // First drop all children that are separators
    var me = this;
    $(el).children('[data-wed--separator-for]').each(function () {
        me._gui_updater.removeNode(this);
    });

    var tag_name = tags[0];

    // If sep is a string, create an appropriate div.
    var $sep;
    if (typeof sep === "string")
        $sep = $('<div class="_text">' + sep + "</div>");
    else
        $sep = $(sep);

    $sep.addClass('_phantom');
    $sep[0].setAttribute('data-wed--separator-for', tag_name);

    var first = true;
    $(el).children('._real').each(function () {
        if (!first)
            me._gui_updater.insertBefore(this.parentNode, $sep.clone()[0],
                                         this);
        else
            first = false;
    });
};

/**
 * An event handler for additions or removals of list
 * elements. Redecorates the list. The parameters after
 * <code>sep</code> are the same as those for
 * <code>added-element</code> and <code>removed-element</code> events
 * in {@link module:domlistener domlistener}.
 *
 * @param {string|jQuery} sep Separator between the elements of the
 * list.
 */
Decorator.prototype.addRemListElementHandler = function (
    sep, $root, $parent, $previous_sibling, $next_sibling, $element) {
    this.listDecorator($parent, sep);
};

/**
 * An event handler for inclusions of lists. The parameters after
 * <code>sep</code> are the same as those for
 * <code>included-element</code> events in {@link module:domlistener
 * domlistener}.
 *
 * @param {string|jQuery} sep Separator between the elements of the
 * list.
 */
Decorator.prototype.includeListHandler = function (
    sep, $root, $tree, $parent, $previous_sibling, $next_sibling, $element) {
    this.listDecorator($element, sep);
};


/**
 * Generic handler for setting <code>contenteditable</code> on nodes
 * included into the tree. The parameters are the same as those for
 * <code>included-element</code> events in {@link module:domlistener
 * domlistener}.
 */
Decorator.prototype.contentEditableHandler = function (
    $root, $parent, $previous_sibling, $next_sibling, $element) {
    function mod(el) {
        // All elements that may get a selection must be focusable to
        // work around bug:
        // https://bugzilla.mozilla.org/show_bug.cgi?id=921444
        el.setAttribute("tabindex", "-1");
        el.setAttribute("contenteditable", el.classList.contains("_real"));
        var children = el.children;
        for(var i = 0, limit = children.length; i < limit; ++i)
            mod(children[i]);
    }
    mod($element[0]);
};

/**
 * Add a start label at the start of an element and end label at the
 * end.
 *
 * @param {jQuery} $root The root of the decorated tree.
 * @param {Node} el The element to decorate.
 * @param {integer} level The level of the labels for this element.<commit_msg>Decorator.listDecorator no longer uses jQuery.<commit_after> /**
  * @module decorator
  * @desc Basic decoration facilities.
  * @author <NAME>
  * @license MPL 2.0
  * @copyright 2013, 2014 Mangalam Research Center for Buddhist Languages
  */
define(/** @lends module:decorator */ function (require, exports, module) {
'use strict';

var util = require("./util");
var $ = require("jquery");
var domutil = require("./domutil");
var jqutil = require("./jqutil");
var transformation = require("./transformation");
var tooltip = require("./gui/tooltip").tooltip;

/**
 * @classdesc A decorator is responsible for adding decorations to a
 * tree of DOM elements. Decorations are GUI elements.
 *
 * @constructor
 * @param {module:domlistener~Listener} domlistener The listener that
 * the decorator must use to know when the DOM tree has changed and
 * must be redecorated.
 * @param {module:wed~Editor} editor The editor instance for which
 * this decorator was created.
 * @param {module:gui_updater~GUIUpdater} gui_updater The updater to
 * use to modify the GUI tree. All modifications to the GUI must go
 * through this updater.
*/
function Decorator(domlistener, editor, gui_updater) {
    this._domlistener = domlistener;
    this._editor = editor;
    this._gui_updater = gui_updater;
}

exports.Decorator = Decorator;

/**
 * Request that the decorator add its event handlers to its listener.
 */
Decorator.prototype.addHandlers = function () {
    this._domlistener.addHandler(
        "added-element",
        "._real, ._phantom, ._phantom_wrap",
        this.contentEditableHandler.bind(this));
};

/**
 * Start listening to changes to the DOM tree.
 *
 * @param {jQuery} $root The DOM root that this decorator listens
 * to. This must be the same root as the root that the this
 * decorator's domlistener listens on and the same root as the root
 * which the GUI updater updates.
 */
Decorator.prototype.startListening = function ($root) {
    var root = $root[0];
    var contents = Array.prototype.slice.call(root.childNodes);
    root.innerHTML = "";
    this._domlistener.startListening();
    this._gui_updater.insertAt(root, 0, contents);
};

/**
 * This function adds a separator between each child element of the
 * element passed as <code>el</code>. The function only considers
 * "._real" elements.
 *
 * @param {Node} el The element to decorate.
 * @param {string|Node} sep A separator.
 */
Decorator.prototype.listDecorator = function (el, sep) {
    // We expect to work with a homogeneous list. That is, all
    // children the same element.
    var name_map = {};
    var child = el.firstElementChild;
    while(child) {
        if (child.classList.contains("_real"))
            name_map[util.getOriginalName(child)] = 1;
        child = child.nextElementSibling;
    }

    var tags = Object.keys(name_map);
    if (tags.length > 1)
        throw new Error("calling listDecorator on a non-homogeneous list.");

    if (tags.length === 0)
        return; // Nothing to work with

    // First drop all children that are separators
    child = el.firstElementChild;
    while(child) {
        // Grab it before the node is removed.
        var next = child.nextElementSibling;
        if (child.hasAttribute("data-wed--separator-for"))
            this._gui_updater.removeNode(child);
        child = next;
    }

    var tag_name = tags[0];

    // If sep is a string, create an appropriate div.
    var sep_node;
    if (typeof sep === "string") {
        sep_node = el.ownerDocument.createElement("div");
        sep_node.appendChild(el.ownerDocument.createTextNode(sep));
    }
    else
        sep_node = sep;

    sep_node.classList.add("_text");
    sep_node.classList.add('_phantom');
    sep_node.setAttribute('data-wed--separator-for', tag_name);

    var first = true;
    child = el.firstElementChild;
    while(child) {
        if (child.classList.contains("_real")) {
            if (!first)
                this._gui_updater.insertBefore(el, sep_node.cloneNode(true),
                                               child);
           else
               first = false;
        }
        child = child.nextElementSibling;
    }
};

/**
 * Generic handler for setting <code>contenteditable</code> on nodes
 * included into the tree. The parameters are the same as those for
 * <code>included-element</code> events in {@link module:domlistener
 * domlistener}.
 */
Decorator.prototype.contentEditableHandler = function (
    $root, $parent, $previous_sibling, $next_sibling, $element) {
    function mod(el) {
        // All elements that may get a selection must be focusable to
        // work around bug:
        // https://bugzilla.mozilla.org/show_bug.cgi?id=921444
        el.setAttribute("tabindex", "-1");
        el.setAttribute("contenteditable", el.classList.contains("_real"));
        var children = el.children;
        for(var i = 0, limit = children.length; i < limit; ++i)
            mod(children[i]);
    }
    mod($element[0]);
};

/**
 * Add a start label at the start of an element and end label at the
 * end.
 *
 * @param {jQuery} $root The root of the decorated tree.
 * @param {Node} el The element to decorate.
 * @param {integer} level The level of the labels for this element.
{'fraction_non_alphanumeric': 0.1228230980751604, 'fraction_numerical': 0.004766269477543538, 'mean_word_length': 3.1220249338874195, 'pattern_counts': {'":': 0, '<': 31, '<?xml version=': 0, '>': 31, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3669006', 'n_tokens_mistral': 3262, 'n_tokens_neox': 3204, 'n_words': 1030}