Returns an object that represents all its params.
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
};
}
Return the tag name, attribute name and a list of options used by the attribute
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
};
}
Return the tagName and a list of attributes used by the tag.
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
};
}
Return the tag info at a given position in the active editor
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();
}
Return the query text of a value.
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;
});