diff --git a/plugins/htmltools/src/com/intellij/htmltools/xml/util/HtmlReferenceProvider.java b/plugins/htmltools/src/com/intellij/htmltools/xml/util/HtmlReferenceProvider.java
index 7d8d0a1752c3..1fcab9b179b3 100644
--- a/plugins/htmltools/src/com/intellij/htmltools/xml/util/HtmlReferenceProvider.java
+++ b/plugins/htmltools/src/com/intellij/htmltools/xml/util/HtmlReferenceProvider.java
@@ -3,6 +3,7 @@ package com.intellij.htmltools.xml.util;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.html.impl.providers.HtmlAttributeValueProvider;
import com.intellij.html.impl.util.MicrodataUtil;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.FileType;
@@ -31,6 +32,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
+import com.intellij.util.containers.JBIterable;
import com.intellij.util.io.URLUtil;
import com.intellij.xml.util.HtmlUtil;
import org.intellij.images.fileTypes.ImageFileTypeManager;
@@ -44,6 +46,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
+import static com.intellij.util.ObjectUtils.doIfNotNull;
+
public class HtmlReferenceProvider extends PsiReferenceProvider {
@NonNls private static final String NAME_ATTR_LOCAL_NAME = "name";
@NonNls private static final String USEMAP_ATTR_NAME = "usemap";
@@ -52,7 +56,7 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
@NonNls private static final String SRC_ATTR_NAME = "src";
@NonNls private static final String JAVASCRIPT_PREFIX = "javascript:";
- private static final FileType[] IMAGE_FILE_TYPES = new FileType[]{ImageFileTypeManager.getInstance().getImageFileType()};
+ public static final FileType[] IMAGE_FILE_TYPES = new FileType[]{ImageFileTypeManager.getInstance().getImageFileType()};
public static final String LABELLEDBY = "aria-labelledby";
public static ElementFilter getFilter() {
@@ -284,7 +288,6 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
return fileType == null ? null : new FileType[]{fileType};
}
- @SuppressWarnings({"HardCodedStringLiteral"})
public static String[] getAttributeValues() {
return new String[] {SRC_ATTR_NAME, HREF_ATTRIBUTE_NAME, USEMAP_ATTR_NAME, "action", "background", "width", "height", "type", "bgcolor", "color", "vlink",
"link", "alink", "text", "name", HtmlUtil.ID_ATTRIBUTE_NAME, HtmlUtil.CLASS_ATTRIBUTE_NAME, FOR_ATTR_NAME, MicrodataUtil.ITEM_REF, "data", "poster", "srcset",
@@ -388,9 +391,15 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
@Nullable
public static ImageInfoReader.Info getImageInfo(@NotNull final XmlTag tag) {
return CachedValuesManager.getCachedValue(tag, () -> {
- final XmlAttribute src = tag.getAttribute(SRC_ATTR_NAME, null);
- if (src != null) {
- final PsiFile psiFile = FileReferenceUtil.findFile(src.getValueElement());
+ PsiElement srcValue = JBIterable.from(HtmlAttributeValueProvider.EP_NAME.getExtensionList())
+ .filterMap(it -> it.getCustomAttributeValue(tag, SRC_ATTR_NAME))
+ .first();
+ if (srcValue == null) {
+ var attr = tag.getAttribute(SRC_ATTR_NAME, null);
+ srcValue = attr != null ? attr.getValueElement() : null;
+ }
+ if (srcValue != null) {
+ final PsiFile psiFile = FileReferenceUtil.findFile(srcValue);
if (psiFile != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile instanceof VirtualFileWithId) {
@@ -398,19 +407,19 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
if (value == null) return null;
return CachedValueProvider.Result.create(
new ImageInfoReader.Info(value.width, value.height, value.bpp, IfsUtil.isSVG(virtualFile)),
- src,
+ srcValue,
virtualFile
);
}
}
- final String srcValue = src.getValue();
- if (srcValue != null && URLUtil.isDataUri(srcValue)) {
- final byte[] bytesFromDataUri = URLUtil.getBytesFromDataUri(srcValue);
+ final String srcValueText = doIfNotNull(srcValue.getText(), StringUtil::unquoteString);
+ if (srcValueText != null && URLUtil.isDataUri(srcValueText)) {
+ final byte[] bytesFromDataUri = URLUtil.getBytesFromDataUri(srcValueText);
if (bytesFromDataUri != null) {
try {
ImageInfoReader.Info info = ImageInfoReader.getInfo(bytesFromDataUri);
if (info != null) {
- return CachedValueProvider.Result.create(info, src);
+ return CachedValueProvider.Result.create(info, srcValue);
}
}
catch (Exception ignored) {
diff --git a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/RequiredAttributesInspectionBase.java b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/RequiredAttributesInspectionBase.java
index 3c85d2c56395..c08dc9c86439 100644
--- a/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/RequiredAttributesInspectionBase.java
+++ b/xml/xml-analysis-impl/src/com/intellij/codeInspection/htmlInspections/RequiredAttributesInspectionBase.java
@@ -18,6 +18,7 @@ package com.intellij.codeInspection.htmlInspections;
import com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightingAwareElementDescriptor;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.util.InspectionMessage;
+import com.intellij.html.impl.providers.HtmlAttributeValueProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsSafe;
@@ -26,6 +27,7 @@ import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlToken;
+import com.intellij.util.containers.JBIterable;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlExtension;
@@ -113,8 +115,10 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
if (!hasAttribute(tag, attrName) &&
!XmlExtension.getExtension(tag.getContainingFile()).isRequiredAttributeImplicitlyPresent(tag, attrName)) {
- LocalQuickFix insertRequiredAttributeIntention = isOnTheFly ? XmlQuickFixFactory.getInstance().insertRequiredAttributeFix(tag, attrName) : null;
- final String localizedMessage = XmlAnalysisBundle.message("xml.inspections.element.doesnt.have.required.attribute", name, attrName);
+ LocalQuickFix insertRequiredAttributeIntention =
+ isOnTheFly ? XmlQuickFixFactory.getInstance().insertRequiredAttributeFix(tag, attrName) : null;
+ final String localizedMessage =
+ XmlAnalysisBundle.message("xml.inspections.element.doesnt.have.required.attribute", name, attrName);
reportOneTagProblem(
tag,
attrName,
@@ -130,6 +134,10 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
}
private static boolean hasAttribute(XmlTag tag, String attrName) {
+ if (JBIterable.from(HtmlAttributeValueProvider.EP_NAME.getExtensionList())
+ .filterMap(it -> it.getCustomAttributeValue(tag, attrName)).first() != null) {
+ return true;
+ }
final XmlAttribute attribute = tag.getAttribute(attrName);
if (attribute == null) return false;
if (attribute.getValueElement() != null) return true;
@@ -149,17 +157,17 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
if (tag instanceof HtmlTag) {
htmlTag = true;
- if(isAdditionallyDeclared(getAdditionalEntries(), name)) return;
+ if (isAdditionallyDeclared(getAdditionalEntries(), name)) return;
}
LocalQuickFix[] fixes;
ProblemHighlightType highlightType;
if (htmlTag) {
- fixes = basicIntention == null ? new LocalQuickFix[] {addAttributeFix} : new LocalQuickFix[]{addAttributeFix, basicIntention};
+ fixes = basicIntention == null ? new LocalQuickFix[]{addAttributeFix} : new LocalQuickFix[]{addAttributeFix, basicIntention};
highlightType = isInjectedWithoutValidation(tag) ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
}
else {
- fixes = basicIntention == null ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[] {basicIntention};
+ fixes = basicIntention == null ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[]{basicIntention};
highlightType = ProblemHighlightType.ERROR;
}
if (isOnTheFly || highlightType != ProblemHighlightType.INFORMATION) {
diff --git a/xml/impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java b/xml/xml-psi-impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java
similarity index 64%
rename from xml/impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java
rename to xml/xml-psi-impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java
index 622bcaa6c172..c7f559a6f31b 100644
--- a/xml/impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java
+++ b/xml/xml-psi-impl/src/com/intellij/html/impl/providers/HtmlAttributeValueProvider.java
@@ -16,7 +16,9 @@
package com.intellij.html.impl.providers;
import com.intellij.openapi.extensions.ExtensionPointName;
+import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlTag;
+import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class HtmlAttributeValueProvider {
@@ -27,9 +29,18 @@ public class HtmlAttributeValueProvider {
* Calculates attribute value. Used when it is impossible to get attribute value as text of PSI element
* @return calculated value
*/
- @Nullable
- public String getCustomAttributeValues(final XmlTag tag, final String attributeName) {
+ public @Nullable String getCustomAttributeValues(@NotNull XmlTag tag, @NotNull String attributeName) {
return null;
}
+
+ /**
+ * Allows to provide an attribute value from a different non-standard attribute to work with in place of a regular one.
+ * It is useful in frameworks, e.g. to provide a directive attribute value instead of {@code src} attribute of {@code
} tag.
+ * @return a custom attribute to use instead of a standard one
+ */
+ public @Nullable PsiElement getCustomAttributeValue(@NotNull XmlTag tag, @NotNull String attributeName) {
+ return null;
+ }
+
}