/
githubmirror
/
brackets
Обзор
Документация
Войти
/
githubmirror
/
brackets
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
src/language/XMLUtils.js
297 строк
13 KB
GABINJUNG
curent -> current (#13915)
04 янв 2018, 10:53
04 янв 2018, 10:53
bfe0812
Код
Авторство
О чём код?
/* * Copyright (c) 2015 - present Adobe Systems Incorporated. All rights reserved. * * 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. * */ define(function (require, exports, module) { "use strict"; // Load dependencies. var TokenUtils = require("utils/TokenUtils"); // Enums of token types. var TOKEN_TAG = 1, TOKEN_ATTR = 2, TOKEN_VALUE = 3; // Regex to find whitespace. var regexWhitespace = /^\s+$/; /** * Returns an object that represents all its params. * * @param {!Token} token CodeMirror token at the current pos * @param {number} tokenType Type of current token * @param {number} offset Offset in current token * @param {Array.<string>} exclusionList List of attributes of a tag or attribute options used by an attribute * @param {string} tagName Name of the current tag * @param {string} attrName Name of the current attribute * @param {boolean} shouldReplace true if we don't want to append ="" to an attribute * @return {!{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 }; } /** * Return the tagName and a list of attributes used by the tag. * * @param {!Editor} editor An instance of active editor * @param {!{line: number, ch: number}} constPos The position of cursor in the active editor * @return {!{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 }; } /** * Return the tag name, attribute name and a list of options used by the attribute * * @param {!Editor} editor An instance of active editor * @param {!{line: number, ch: number}} pos Position of cursor in the editor * @return {!{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 }; } /** * Return the tag info at a given position in the active editor * * @param {!Editor} editor Instance of active editor * @param {!{line: number, ch: number}} pos Position of cursor in the editor * @return {!{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(); } /** * Return the query text of a value. * * @param {!{token: Object, tokenType: number, offset: number, exclusionList: Array.<string>, tagName: string, attrName: string, shouldReplace: boolean}} * @return {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; });