Modules (188)

XMLUtils

Description

Dependencies

Functions

Private

_createTagInfo

Returns an object that represents all its params.

token non-nullable Token
CodeMirror token at the current pos
tokenType number
Type of current token
offset number
Offset in current token
exclusionList Array.<string>
List of attributes of a tag or attribute options used by an attribute
tagName string
Name of the current tag
attrName string
Name of the current attribute
shouldReplace boolean
true if we don't want to append ="" to an attribute
Returns: !{token: Token,tokenType: int,offset: int,exclusionList: Array.<string>,tagName: string,attrName: string,shouldReplace: boolean}
    function _createTagInfo(token, tokenType, offset, exclusionList, tagName, attrName, shouldReplace) {
        return {
            token: token || null,
            tokenType: tokenType || null,
            offset: offset || 0,
            exclusionList: exclusionList || [],
            tagName: tagName || "",
            attrName: attrName || "",
            shouldReplace: shouldReplace || false
        };
    }
Private

_getTagAttributeValue

Return the tag name, attribute name and a list of options used by the attribute

editor non-nullable Editor
An instance of active editor
pos non-nullable {line: number, ch: number}
Position of cursor in the editor
Returns: !{tagName: string,attrName: string,exclusionList: Array.<string>}
    function _getTagAttributeValue(editor, pos) {
        var ctx, tagName, attrName, exclusionList = [], offset, textBefore, textAfter;

        ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);
        offset = TokenUtils.offsetInToken(ctx);

        // To support multiple options on the same attribute, we have
        // to break the value, these values will not be available then.
        if (ctx.token.type === "string" && /\s+/.test(ctx.token.string)) {
            textBefore = ctx.token.string.substr(1, offset);
            textAfter = ctx.token.string.substr(offset);

            // Remove quote from end of the string.
            if (/^['"]$/.test(ctx.token.string.substr(-1, 1))) {
                textAfter = textAfter.substr(0, textAfter.length - 1);
            }

            // Split the text before and after the offset, skipping the current query.
            exclusionList = exclusionList.concat(textBefore.split(/\s+/).slice(0, -1));
            exclusionList = exclusionList.concat(textAfter.split(/\s+/));

            // Filter through the list removing empty strings.
            exclusionList = exclusionList.filter(function (value) {
                if (value.length > 0) {
                    return true;
                }
            });
        }

        // Look-back and find tag and attributes.
        while (TokenUtils.movePrevToken(ctx)) {
            if (ctx.token.type === "tag bracket") {
                // Disallow hints in closing tags.
                if (ctx.token.string === "</") {
                    return null;
                }
                // Stop when closing bracket of another tag or opening bracket of its own in encountered.
                if (ctx.token.string.indexOf(">") >= 0 || ctx.token.string === "<") {
                    break;
                }
            }

            // Get the first previous attribute.
            if (ctx.token.type === "attribute" && !attrName) {
                attrName = ctx.token.string;
            }

            // Stop if we get a bracket after tag.
            if (ctx.token.type === "tag") {
                tagName = ctx.token.string;
                if (TokenUtils.movePrevToken(ctx)) {
                    if (ctx.token.type === "tag bracket" && ctx.token.string === "<") {
                        break;
                    }
                    return null;
                }
            }
        }

        return {
            tagName: tagName,
            attrName: attrName,
            exclusionList: exclusionList
        };
    }
Private

_getTagAttributes

Return the tagName and a list of attributes used by the tag.

editor non-nullable Editor
An instance of active editor
constPos non-nullable {line: number, ch: number}
The position of cursor in the active editor
Returns: !{tagName: string,exclusionList: Array.<string>,shouldReplace: boolean}
    function _getTagAttributes(editor, constPos) {
        var pos, ctx, ctxPrev, ctxNext, ctxTemp, tagName, exclusionList = [], shouldReplace;

        pos = $.extend({}, constPos);
        ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);

        // Stop if the cursor is before = or an attribute value.
        ctxTemp = $.extend(true, {}, ctx);
        if (ctxTemp.token.type === null && regexWhitespace.test(ctxTemp.token.string)) {
            if (TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctxTemp)) {
                if ((ctxTemp.token.type === null && ctxTemp.token.string === "=") ||
                        ctxTemp.token.type === "string") {
                    return null;
                }
                TokenUtils.moveSkippingWhitespace(TokenUtils.movePrevToken, ctxTemp);
            }
        }

        // Incase an attribute is followed by an equal sign, shouldReplace will be used
        // to prevent from appending ="" again.
        if (ctxTemp.token.type === "attribute") {
            if (TokenUtils.moveSkippingWhitespace(TokenUtils.moveNextToken, ctxTemp)) {
                if (ctxTemp.token.type === null && ctxTemp.token.string === "=") {
                    shouldReplace = true;
                }
            }
        }

        // Look-Back and get the attributes and tag name.
        pos = $.extend({}, constPos);
        ctxPrev = TokenUtils.getInitialContext(editor._codeMirror, pos);
        while (TokenUtils.movePrevToken(ctxPrev)) {
            if (ctxPrev.token.type && ctxPrev.token.type.indexOf("tag bracket") >= 0) {
                // Disallow hints in closed tag and inside tag content
                if (ctxPrev.token.string === "</" || ctxPrev.token.string.indexOf(">") !== -1) {
                    return null;
                }
            }

            // Get attributes.
            if (ctxPrev.token.type === "attribute") {
                exclusionList.push(ctxPrev.token.string);
            }

            // Get tag.
            if (ctxPrev.token.type === "tag") {
                tagName = ctxPrev.token.string;
                if (TokenUtils.movePrevToken(ctxPrev)) {
                    if (ctxPrev.token.type === "tag bracket" && ctxPrev.token.string === "<") {
                        break;
                    }
                    return null;
                }
            }
        }

        // Look-Ahead and find rest of the attributes.
        pos = $.extend({}, constPos);
        ctxNext = TokenUtils.getInitialContext(editor._codeMirror, pos);
        while (TokenUtils.moveNextToken(ctxNext)) {
            if (ctxNext.token.type === "string" && ctxNext.token.string === "\"") {
                return null;
            }

            // Stop on closing bracket of its own tag or opening bracket of next tag.
            if (ctxNext.token.type === "tag bracket" &&
                    (ctxNext.token.string.indexOf(">") >= 0 || ctxNext.token.string === "<")) {
                break;
            }
            if (ctxNext.token.type === "attribute" && exclusionList.indexOf(ctxNext.token.string) === -1) {
                exclusionList.push(ctxNext.token.string);
            }
        }
        return {
            tagName: tagName,
            exclusionList: exclusionList,
            shouldReplace: shouldReplace
        };
    }
Public API

getTagInfo

Return the tag info at a given position in the active editor

editor non-nullable Editor
Instance of active editor
pos non-nullable {line: number, ch: number}
Position of cursor in the editor
Returns: !{token: Object,tokenType: number,offset: number,exclusionList: Array.<string>,tagName: string,attrName: string,shouldReplace: boolean}
    function getTagInfo(editor, pos) {
        var ctx, offset, tagAttrs, tagAttrValue;

        ctx = TokenUtils.getInitialContext(editor._codeMirror, pos);
        offset = TokenUtils.offsetInToken(ctx);

        if (ctx.token && ctx.token.type === "tag bracket" && ctx.token.string === "<") {
            // Returns tagInfo when an angle bracket is created.
            return _createTagInfo(ctx.token, TOKEN_TAG);
        } else if (ctx.token && ctx.token.type === "tag") {
            // Return tagInfo when a tag is created.
            if (TokenUtils.movePrevToken(ctx)) {
                if (ctx.token.type === "tag bracket" && ctx.token.string === "<") {
                    TokenUtils.moveNextToken(ctx);
                    return _createTagInfo(ctx.token, TOKEN_TAG, offset);
                }
            }
        } else if (ctx.token && (ctx.token.type === "attribute" ||
                                 (ctx.token.type === null && regexWhitespace.test(ctx.token.string)))) {
            // Return tagInfo when an attribute is created.
            tagAttrs = _getTagAttributes(editor, pos);
            if (tagAttrs && tagAttrs.tagName) {
                return _createTagInfo(ctx.token, TOKEN_ATTR, offset, tagAttrs.exclusionList, tagAttrs.tagName, null, tagAttrs.shouldReplace);
            }
        } else if (ctx.token && ((ctx.token.type === null && ctx.token.string === "=") ||
                                 (ctx.token.type === "string" && /^['"]$/.test(ctx.token.string.charAt(0))))) {
            // Return tag info when an attribute value is created.
            // Allow no hints if the cursor is outside the value.
            if (ctx.token.type === "string" &&
                    /^['"]$/.test(ctx.token.string.substr(-1, 1)) &&
                    ctx.token.string.length !== 1 &&
                    ctx.token.end === pos.ch) {
                return _createTagInfo();
            }

            tagAttrValue = _getTagAttributeValue(editor, pos);
            if (tagAttrValue && tagAttrValue.tagName && tagAttrValue.attrName) {
                return _createTagInfo(ctx.token, TOKEN_VALUE, offset, tagAttrValue.exclusionList, tagAttrValue.tagName, tagAttrValue.attrName);
            }
        }
        return _createTagInfo();
    }
Public API

getValueQuery

Return the query text of a value.

non-nullable {token: Object, tokenType: number, offset: number, exclusionList: Array.<string>, tagName: string, attrName: string, shouldReplace: boolean}
Returns: string
The query to use to matching hints.
    function getValueQuery(tagInfo) {
        var query;
        if (tagInfo.token.string === "=") {
            return "";
        }
        // Remove quotation marks in query.
        query = tagInfo.token.string.substr(1, tagInfo.offset - 1);

        // Get the last option to use as a query to support multiple options.
        return query.split(/\s+/).slice(-1)[0];
    }

    // Expose public API.
    exports.getTagInfo      = getTagInfo;
    exports.getValueQuery   = getValueQuery;
    exports.regexWhitespace = regexWhitespace;
    exports.TOKEN_TAG       = TOKEN_TAG;
    exports.TOKEN_ATTR      = TOKEN_ATTR;
    exports.TOKEN_VALUE     = TOKEN_VALUE;
});