File: /var/www/tana/frontend/node_modules/svgo/lib/svgo/jsAPI.js
'use strict';
var EXTEND = require('whet.extend');
var JSAPI = module.exports = function(data, parentNode) {
    EXTEND(this, data);
    if (parentNode) {
        Object.defineProperty(this, 'parentNode', {
            writable: true,
            value: parentNode
        });
    }
};
/**
 * Perform a deep clone of this node.
 *
 * @return {Object} element
 */
JSAPI.prototype.clone = function() {
    var node = this;
    var nodeData = {};
    Object.keys(node).forEach(function(key) {
        if (key !== 'content') {
            nodeData[key] = node[key];
        }
    });
    // Deep-clone node data
    // This is still faster than using EXTEND(true…)
    nodeData = JSON.parse(JSON.stringify(nodeData));
    // parentNode gets set to a proper object by the parent clone,
    // but it needs to be true/false now to do the right thing
    // in the constructor.
    var clonedNode = new JSAPI(nodeData, !!node.parentNode);
    if (node.content) {
        clonedNode.content = node.content.map(function(childNode) {
            var clonedChild = childNode.clone();
            clonedChild.parentNode = clonedNode;
            return clonedChild;
        });
    }
    return clonedNode;
};
/**
 * Determine if item is an element
 * (any, with a specific name or in a names array).
 *
 * @param {String|Array} [param] element name or names arrays
 * @return {Boolean}
 */
JSAPI.prototype.isElem = function(param) {
    if (!param) return !!this.elem;
    if (Array.isArray(param)) return !!this.elem && (param.indexOf(this.elem) > -1);
    return !!this.elem && this.elem === param;
};
/**
 * Renames an element
 *
 * @param {String} name new element name
 * @return {Object} element
 */
JSAPI.prototype.renameElem = function(name) {
    if (name && typeof name === 'string')
        this.elem = this.local = name;
    return this;
};
/**
 * Determine if element is empty.
 *
 * @return {Boolean}
 */
 JSAPI.prototype.isEmpty = function() {
    return !this.content || !this.content.length;
};
/**
 * Changes content by removing elements and/or adding new elements.
 *
 * @param {Number} start Index at which to start changing the content.
 * @param {Number} n Number of elements to remove.
 * @param {Array|Object} [insertion] Elements to add to the content.
 * @return {Array} Removed elements.
 */
 JSAPI.prototype.spliceContent = function(start, n, insertion) {
    if (arguments.length < 2) return [];
    if (!Array.isArray(insertion))
        insertion = Array.apply(null, arguments).slice(2);
    insertion.forEach(function(inner) { inner.parentNode = this }, this);
    return this.content.splice.apply(this.content, [start, n].concat(insertion));
};
/**
 * Determine if element has an attribute
 * (any, or by name or by name + value).
 *
 * @param {String} [name] attribute name
 * @param {String} [val] attribute value (will be toString()'ed)
 * @return {Boolean}
 */
 JSAPI.prototype.hasAttr = function(name, val) {
    if (!this.attrs || !Object.keys(this.attrs).length) return false;
    if (!arguments.length) return !!this.attrs;
    if (val !== undefined) return !!this.attrs[name] && this.attrs[name].value === val.toString();
    return !!this.attrs[name];
};
/**
 * Determine if element has an attribute by local name
 * (any, or by name or by name + value).
 *
 * @param {String} [localName] local attribute name
 * @param {Number|String|RegExp|Function} [val] attribute value (will be toString()'ed or executed, otherwise ignored)
 * @return {Boolean}
 */
 JSAPI.prototype.hasAttrLocal = function(localName, val) {
    if (!this.attrs || !Object.keys(this.attrs).length) return false;
    if (!arguments.length) return !!this.attrs;
    var callback;
    switch (val != null && val.constructor && val.constructor.name) {
        case 'Number':   // same as String
        case 'String':   callback = stringValueTest; break;
        case 'RegExp':   callback = regexpValueTest; break;
        case 'Function': callback = funcValueTest; break;
        default:         callback = nameTest;
    }
    return this.someAttr(callback);
    function nameTest(attr) {
        return attr.local === localName;
    }
    function stringValueTest(attr) {
        return attr.local === localName && val == attr.value;
    }
    function regexpValueTest(attr) {
        return attr.local === localName && val.test(attr.value);
    }
    function funcValueTest(attr) {
        return attr.local === localName && val(attr.value);
    }
};
/**
 * Get a specific attribute from an element
 * (by name or name + value).
 *
 * @param {String} name attribute name
 * @param {String} [val] attribute value (will be toString()'ed)
 * @return {Object|Undefined}
 */
 JSAPI.prototype.attr = function(name, val) {
    if (!this.hasAttr() || !arguments.length) return undefined;
    if (val !== undefined) return this.hasAttr(name, val) ? this.attrs[name] : undefined;
    return this.attrs[name];
};
/**
 * Get computed attribute value from an element
 *
 * @param {String} name attribute name
 * @return {Object|Undefined}
 */
 JSAPI.prototype.computedAttr = function(name, val) {
    /* jshint eqnull: true */
    if (!arguments.length) return;
    for (var elem = this; elem && (!elem.hasAttr(name) || !elem.attr(name).value); elem = elem.parentNode);
    if (val != null) {
        return elem ? elem.hasAttr(name, val) : false;
    } else if (elem && elem.hasAttr(name)) {
        return elem.attrs[name].value;
    }
};
/**
 * Remove a specific attribute.
 *
 * @param {String|Array} name attribute name
 * @param {String} [val] attribute value
 * @return {Boolean}
 */
 JSAPI.prototype.removeAttr = function(name, val, recursive) {
    if (!arguments.length) return false;
    if (Array.isArray(name)) name.forEach(this.removeAttr, this);
    if (!this.hasAttr(name)) return false;
    if (!recursive && val && this.attrs[name].value !== val) return false;
    delete this.attrs[name];
    if (!Object.keys(this.attrs).length) delete this.attrs;
    return true;
};
/**
 * Add attribute.
 *
 * @param {Object} [attr={}] attribute object
 * @return {Object|Boolean} created attribute or false if no attr was passed in
 */
 JSAPI.prototype.addAttr = function(attr) {
    attr = attr || {};
    if (attr.name === undefined ||
        attr.prefix === undefined ||
        attr.local === undefined
    ) return false;
    this.attrs = this.attrs || {};
    this.attrs[attr.name] = attr;
    return this.attrs[attr.name];
};
/**
 * Iterates over all attributes.
 *
 * @param {Function} callback callback
 * @param {Object} [context] callback context
 * @return {Boolean} false if there are no any attributes
 */
 JSAPI.prototype.eachAttr = function(callback, context) {
    if (!this.hasAttr()) return false;
    for (var name in this.attrs) {
        callback.call(context, this.attrs[name]);
    }
    return true;
};
/**
 * Tests whether some attribute passes the test.
 *
 * @param {Function} callback callback
 * @param {Object} [context] callback context
 * @return {Boolean} false if there are no any attributes
 */
 JSAPI.prototype.someAttr = function(callback, context) {
    if (!this.hasAttr()) return false;
    for (var name in this.attrs) {
        if (callback.call(context, this.attrs[name])) return true;
    }
    return false;
};