API Docs for: 3.11.0-git
Show:

File: src/sm-editor/js/editor-dom.js

/*jshint expr:true, onevar:false */

/**
Provides the `Editor.DOM` utility class.

@module gallery-sm-editor
@submodule gallery-sm-editor-dom
**/

/**
DOM utility methods for `Editor.Base`

@class Editor.DOM
**/

var EditorDOM = {};

/**
Copies styles from a node to another node

@method copyStyles
@param {HTMLElement|Node} from
@param {HTMLElement|Node} to
@param {Array} styles
@param {Object} [options]
    @param {Boolean} [options.explicit=false] When set to `true` copy only
        explicitly set properties from the source node. IOW, don't use
        computedStyle.
    @param {Boolean} [options.overwrite=false] When set to `true`
        properties from the source node will overwrite the same property
        set on the destination node.
**/
EditorDOM.copyStyles = function(from, to, styles, options) {
    var newStyles = {},
        explicit = options && options.explicit,
        overwrite = options && options.overwrite;

    from = Y.one(from);
    to = Y.one(to);

    if (!EditorDOM.isElementNode(from) || !EditorDOM.isElementNode(to)) {
        return;
    }

    Y.Array.each(styles, function(prop) {
        var newVal = explicit ? from._node.style[prop] : from.getStyle(prop);

        if ('' !== newVal && (overwrite || '' === to._node.style[prop])) {
            newStyles[prop] = newVal;
        }
    });

    to.setStyles(newStyles);
};


/**
Returns true if the given node is an element node, false otherwise

@method isElementNode
@param {HTMLNode|Node} node
@return {Boolean} true if the given node is an element node, false otherwise
@static
**/
EditorDOM.isElementNode = function(node) {
    node = Y.one(node);

    return node._node && 1 === node._node.nodeType;
};


/**
Returns true if the given node is empty

Nodes containing only returns, tabs or linefeeds are considered empty
Nodes containing only whitespace or breaks (br) are not considered empty

@method isEmptyNode
@param {HTMLNode|Node} node
@return {Boolean} true if the given node is a empty, false otherwise
@static
**/
EditorDOM.isEmptyNode = function(node) {
    node = Y.one(node);

    if (node && node.test('br')) {
        return false;
    } else {
        return (/^[^\S ]*$/).test(node ? node.get('text') : '') && !node.one('br');
    }
};


/**
Returns true if the given node is a text node, false otherwise

@method isTextNode
@param {HTMLNode|Node} node
@return {Boolean} true if the given node is a text node, false otherwise
@static
**/
EditorDOM.isTextNode = function(node) {
    node = Y.one(node);

    return node._node && 3 === node._node.nodeType;
};


/**
Returns the maximum offset of a given node as determined by the type of node.

Element nodes will return the number of childNodes
Text nodes will return the length of the text

@method maxOffset
@param {HTMLNode|Node} node
@return {Number} Number of child nodes or length of text
@static
**/
EditorDOM.maxOffset = function(node) {
    node = Y.one(node);

    return node.get('childNodes').size() || node.get('length');
};


/**
Splits the given node at the specified offset

@method split
@param {Node} node The node to split
@param {Number|Node} offset Position to split the node.
    For text nodes this is numerical offset, for element nodes can be a
    a number referencing a childNode of `node` or a childNode reference.
@return {Node} Node reference to the node created after splitting. It will
    be the nextSibling of `node`. If offset is not valid, the original `node`
    is returned.
**/
EditorDOM.split = function(node, offset) {
    var childNodes = node.get('childNodes'),
        splitNode;

    node = Y.one(node);

    if (offset && offset._node) {
        offset = childNodes.indexOf(offset);
    } else {
        offset = parseInt(offset, 10);
    }

    if (isNaN(offset) || offset < 0 || offset > EditorDOM.maxOffset(node)) {
        return node;
    }

    if (EditorDOM.isTextNode(node)) {
        return Y.one(node._node.splitText(offset));
    } else {
        splitNode = node.cloneNode(false).append(childNodes.splice(offset));
        node.insert(splitNode, 'after');

        return splitNode;
    }
};


Y.namespace('Editor').DOM = EditorDOM;