diff --git a/platform/platform-resources/src/META-INF/XmlPlugin.xml b/platform/platform-resources/src/META-INF/XmlPlugin.xml index 87eed975a9bc..dbd7e8ffd2cd 100644 --- a/platform/platform-resources/src/META-INF/XmlPlugin.xml +++ b/platform/platform-resources/src/META-INF/XmlPlugin.xml @@ -21,6 +21,11 @@ + + + + + type attribute + * @return true if language should not be injected + */ + boolean isLanguageInjectionDenied(@NotNull XmlTag scriptTag, @NotNull Language language); +} diff --git a/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptInjectionBlockerExtension.java b/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptInjectionBlockerExtension.java new file mode 100644 index 000000000000..1a99a5845489 --- /dev/null +++ b/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptInjectionBlockerExtension.java @@ -0,0 +1,62 @@ +/* + * Copyright 2000-2015 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.psi.impl.source.html; + +import com.intellij.lang.Language; +import com.intellij.lang.LanguageExtension; +import com.intellij.psi.xml.XmlTag; +import org.jetbrains.annotations.NotNull; + +import java.util.Collection; + +/** + * Language extension to block script injection into HTML tag <script> when this language exists on file's + * {@link com.intellij.psi.FileViewProvider}. + * + * @author Ilya.Kazakevich + */ +public final class HtmlScriptInjectionBlockerExtension extends LanguageExtension { + private static final HtmlScriptInjectionBlockerExtension INSTANCE = new HtmlScriptInjectionBlockerExtension(); + + private HtmlScriptInjectionBlockerExtension() { + super("com.intellij.html.htmlScriptInjectionBlocker"); + } + + + /** + * Checks if language injection to this tag is explicitly denied by one or more @link HtmlScriptInjectionBlocker extension points} + * + * @param xmlTag <script> tag + * @param language lang user wants to inject (probably obtained via {@link HtmlScriptLanguageInjector} + * @return true if injection denied by extension point + */ + + public static boolean isInjectionBlocked(@NotNull XmlTag xmlTag, @NotNull Language language) { + + Collection allFileLanguages = xmlTag.getContainingFile().getViewProvider().getLanguages(); + + for (Language fileLanguage : allFileLanguages) { + for (HtmlScriptInjectionBlocker blocker : INSTANCE.allForLanguage(fileLanguage)) { + if (blocker.isLanguageInjectionDenied(xmlTag, language)) { + // Language exists, but denied by EP + return true; + } + } + } + // Language exists and not denied + return false; + } +} diff --git a/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptLanguageInjector.java b/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptLanguageInjector.java index d874118395b1..701046da40c3 100644 --- a/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptLanguageInjector.java +++ b/xml/impl/src/com/intellij/psi/impl/source/html/HtmlScriptLanguageInjector.java @@ -17,7 +17,6 @@ package com.intellij.psi.impl.source.html; import com.intellij.lang.Language; import com.intellij.lang.LanguageUtil; -import com.intellij.lang.StdLanguages; import com.intellij.lang.injection.MultiHostInjector; import com.intellij.lang.injection.MultiHostRegistrar; import com.intellij.openapi.util.TextRange; @@ -27,24 +26,47 @@ import com.intellij.psi.xml.XmlTag; import com.intellij.psi.xml.XmlText; import com.intellij.xml.util.HtmlUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Collection; import java.util.Collections; import java.util.List; public class HtmlScriptLanguageInjector implements MultiHostInjector { + + + /** + * Finds language to be injected into <script> tag + * + * @param xmlTag <script> tag + * @return language to inject or null if no language found or not a script tag at all + */ + @Nullable + public static Language getScriptLanguageToInject(@NotNull XmlTag xmlTag) { + if (!HtmlUtil.isScriptTag(xmlTag)) { + return null; + } + String mimeType = xmlTag.getAttributeValue("type"); + Collection languages = Language.findInstancesByMimeType(mimeType); + return !languages.isEmpty() ? languages.iterator().next() : Language.ANY; + } + @Override public void getLanguagesToInject(@NotNull MultiHostRegistrar registrar, @NotNull PsiElement host) { if (!host.isValid() || !(host instanceof XmlText) || !HtmlUtil.isHtmlTagContainingFile(host)) { return; } XmlTag scriptTag = ((XmlText)host).getParentTag(); - if (scriptTag == null || !HtmlUtil.isScriptTag(scriptTag)) { + + if (scriptTag == null) { return; } - String mimeType = scriptTag.getAttributeValue("type"); - Collection languages = Language.findInstancesByMimeType(mimeType); - Language language = !languages.isEmpty() ? languages.iterator().next() : Language.ANY; + final Language language = getScriptLanguageToInject(scriptTag); + + if (language == null || HtmlScriptInjectionBlockerExtension.isInjectionBlocked(scriptTag, language)) { + return; + } + if (LanguageUtil.isInjectableLanguage(language)) { registrar .startInjecting(language)