<commit_before>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Famous Industries Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

var ElementCache = require('./ElementCache');
var math = require('./Math');
var vendorPrefix = require('../utilities/vendorPrefix');
var eventMap = require('./events/EventMap');

var TRANSFORM = null;

/**
 * DOMRenderer is a class responsible for adding elements
 * to the DOM and writing to those elements.
 * There is a DOMRenderer per context, represented as an
 * element and a selector. It is instantiated in the
 * context class.
 *
 * @class DOMRenderer
 *
 * @param {HTMLElement} element an element.
 * @param {String} selector the selector of the element.
 * @param {Compositor} compositor the compositor controlling the renderer
 */
function DOMRenderer (element, selector, compositor) {
    var _this = this;

    element.classList.add('famous-dom-renderer');

    TRANSFORM = TRANSFORM || vendorPrefix('transform');
    this._compositor = compositor; // a reference to the compositor

    this._target = null; // a register for holding the current
                         // element that the Renderer is operating
                         // upon

    this._parent = null; // a register for holding the parent
                         // of the target

    this._path = null; // a register for holding the path of the target
                       // this register must be set first, and then
                       // children, target, and parent are all looked
                       // up from that.

    this._children = []; // a register for holding the children of the
                         // current target.

    this._root = new ElementCache(element, selector); // the root
                                                      // of the dom tree that this
                                                      // renderer is responsible
                                                      // for

    this._boundTriggerEvent = function (ev) {
        return _this._triggerEvent(ev);
    };

    this._selector = selector;

    this._elements = {};

    this._elements[selector] = this._root;

    this.perspectiveTransform = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
    this._VPtransform = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

    this._lastEv = null;
}


/**
 * Attaches an EventListener to the element associated with the passed in path.
 * Prevents the default browser action on all subsequent events if
 * `preventDefault` is truthy.
 * All incoming events will be forwarded to the compositor by invoking the
 * `sendEvent` method.
 * Delegates events if possible by attaching the event listener to the context.
 *
 * @method
 *
 * @param {String} type DOM event type (e.g. click, mouseover).
 * @param {Boolean} preventDefault Whether or not the default browser action should be prevented.
 *
 * @return {undefined} undefined
 */
DOMRenderer.prototype.subscribe = function subscribe(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.subscribe[type] = true;
};

/**
 * Unsubscribes from all events that are of the specified type.
 *
 * @method
 *
 * @param  {String} type    Event type to unsubscribe from.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.unsubscribe = function unsubscribe(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.subscribe[type] = false;
};

/**
 * Used to preventDefault if an event of the specified type is being emitted on
 * the currently loaded target.
 *
 * @method
 *
 * @param  {String} type    The type of events that should be prevented.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.preventDefault = function preventDefault(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.preventDefault[type] = true;
};

/**
 * Used to undo a previous call to preventDefault. No longer `preventDefault`
 * for this event on the loaded target.
 *
 * @method
 * @private
 *
 * @param  {String} type    The event type that should no longer be affected by
 *                          `preventDefault`.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.allowDefault = function allowDefault(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.preventDefault[type] = false;
};

/**
 * Internal helper function used for adding an event listener for the the
 * currently loaded ElementCache.
 *
 * If the event can be delegated as specified in the {@link EventMap}, the
 * bound {@link _triggerEvent} function will be added as a listener on the
 * root element. Otherwise, the listener will be added directly to the target
 * element.
 *
 * @private
 * @method
 *
 * @param  {String} type    The event type to listen to (e.g. click).
 * @return {undefined}      undefined
 */
DOMRenderer.prototype._listen = function _listen(type) {
    this._assertTargetLoaded();

    if (
        !this._target.listeners[type] && !this._root.listeners[type]
    ) {
        // FIXME Add to content DIV if available
        var target = eventMap[type][1] ? this._root : this._target;
        target.listeners[type] = this._boundTriggerEvent;
        target.element.addEventListener(type, this._boundTriggerEvent);
    }
};

DOMRenderer.prototype.unsubscribe = function unsubscribe(type) {
    this._assertTargetLoaded();
    this._target.subscribe[type] = false;

    if (
        this._target.listeners[type] || this._root.listeners[type]
    ) {
        var target = eventMap[type][1] ? this._root : this._target;
        target.listeners[type] = null;
        target.element.removeEventListener(type, this._boundTriggerEvent);
    }
};

/**
 * Function to be added using `addEventListener` to the corresponding
 * DOMElement.
 *
 * @method
 * @private
 *
 * @param {Event} ev DOM Event payload
 *
 * @return {undefined} undefined
 */
DOMRenderer.prototype._triggerEvent = function _triggerEvent(ev) {
    if (this._lastEv === ev) return;

    // Use ev.path, which is an array of Elements (polyfilled if needed).<commit_msg>docs: documentation for DOMRenderer.prototype.unsubscribe<commit_after>/**
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Famous Industries Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

'use strict';

var ElementCache = require('./ElementCache');
var math = require('./Math');
var vendorPrefix = require('../utilities/vendorPrefix');
var eventMap = require('./events/EventMap');

var TRANSFORM = null;

/**
 * DOMRenderer is a class responsible for adding elements
 * to the DOM and writing to those elements.
 * There is a DOMRenderer per context, represented as an
 * element and a selector. It is instantiated in the
 * context class.
 *
 * @class DOMRenderer
 *
 * @param {HTMLElement} element an element.
 * @param {String} selector the selector of the element.
 * @param {Compositor} compositor the compositor controlling the renderer
 */
function DOMRenderer (element, selector, compositor) {
    var _this = this;

    element.classList.add('famous-dom-renderer');

    TRANSFORM = TRANSFORM || vendorPrefix('transform');
    this._compositor = compositor; // a reference to the compositor

    this._target = null; // a register for holding the current
                         // element that the Renderer is operating
                         // upon

    this._parent = null; // a register for holding the parent
                         // of the target

    this._path = null; // a register for holding the path of the target
                       // this register must be set first, and then
                       // children, target, and parent are all looked
                       // up from that.

    this._children = []; // a register for holding the children of the
                         // current target.

    this._root = new ElementCache(element, selector); // the root
                                                      // of the dom tree that this
                                                      // renderer is responsible
                                                      // for

    this._boundTriggerEvent = function (ev) {
        return _this._triggerEvent(ev);
    };

    this._selector = selector;

    this._elements = {};

    this._elements[selector] = this._root;

    this.perspectiveTransform = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);
    this._VPtransform = new Float32Array([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]);

    this._lastEv = null;
}


/**
 * Attaches an EventListener to the element associated with the passed in path.
 * Prevents the default browser action on all subsequent events if
 * `preventDefault` is truthy.
 * All incoming events will be forwarded to the compositor by invoking the
 * `sendEvent` method.
 * Delegates events if possible by attaching the event listener to the context.
 *
 * @method
 *
 * @param {String} type DOM event type (e.g. click, mouseover).
 * @param {Boolean} preventDefault Whether or not the default browser action should be prevented.
 *
 * @return {undefined} undefined
 */
DOMRenderer.prototype.subscribe = function subscribe(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.subscribe[type] = true;
};

/**
 * Unsubscribes from all events that are of the specified type.
 *
 * @method
 *
 * @param  {String} type    Event type to unsubscribe from.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.unsubscribe = function unsubscribe(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.subscribe[type] = false;
};

/**
 * Used to preventDefault if an event of the specified type is being emitted on
 * the currently loaded target.
 *
 * @method
 *
 * @param  {String} type    The type of events that should be prevented.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.preventDefault = function preventDefault(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.preventDefault[type] = true;
};

/**
 * Used to undo a previous call to preventDefault. No longer `preventDefault`
 * for this event on the loaded target.
 *
 * @method
 * @private
 *
 * @param  {String} type    The event type that should no longer be affected by
 *                          `preventDefault`.
 * @return {undefined}      undefined
 */
DOMRenderer.prototype.allowDefault = function allowDefault(type) {
    this._assertTargetLoaded();
    this._listen(type);
    this._target.preventDefault[type] = false;
};

/**
 * Internal helper function used for adding an event listener for the the
 * currently loaded ElementCache.
 *
 * If the event can be delegated as specified in the {@link EventMap}, the
 * bound {@link _triggerEvent} function will be added as a listener on the
 * root element. Otherwise, the listener will be added directly to the target
 * element.
 *
 * @private
 * @method
 *
 * @param  {String} type    The event type to listen to (e.g. click).
 * @return {undefined}      undefined
 */
DOMRenderer.prototype._listen = function _listen(type) {
    this._assertTargetLoaded();

    if (
        !this._target.listeners[type] && !this._root.listeners[type]
    ) {
        // FIXME Add to content DIV if available
        var target = eventMap[type][1] ? this._root : this._target;
        target.listeners[type] = this._boundTriggerEvent;
        target.element.addEventListener(type, this._boundTriggerEvent);
    }
};

/**
 * Removes an EventListener of given type from the element on which it was
 * registered.
 *
 * @method
 *
 * @param {String} type DOM event type (e.g. click, mouseover).
 *
 * @return {undefined} undefined
 */
DOMRenderer.prototype.unsubscribe = function unsubscribe(type) {
    this._assertTargetLoaded();
    this._target.subscribe[type] = false;

    if (
        this._target.listeners[type] || this._root.listeners[type]
    ) {
        var target = eventMap[type][1] ? this._root : this._target;
        target.listeners[type] = null;
        target.element.removeEventListener(type, this._boundTriggerEvent);
    }
};

/**
 * Function to be added using `addEventListener` to the corresponding
 * DOMElement.
 *
 * @method
 * @private
 *
 * @param {Event} ev DOM Event payload
 *
 * @return {undefined} undefined
 */
DOMRenderer.prototype._triggerEvent = function _triggerEvent(ev) {
    if (this._lastEv === ev) return;

    // Use ev.path, which is an array of Elements (polyfilled if needed).
{'fraction_non_alphanumeric': 0.09663951817124085, 'fraction_numerical': 0.00574909314899733, 'mean_word_length': 2.8533755274261603, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 12, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7561028', 'n_tokens_mistral': 3915, 'n_tokens_neox': 3754, 'n_words': 1517}