diff options
Diffstat (limited to 'bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java')
-rw-r--r-- | bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java | 91 |
1 files changed, 86 insertions, 5 deletions
diff --git a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java index c4d794fb81..9acadf0f0a 100644 --- a/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java +++ b/bundles/org.eclipse.wst.html.core/src/org/eclipse/wst/html/core/internal/validate/HTMLAttributeValidator.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2004, 2013 IBM Corporation and others. + * Copyright (c) 2004, 2014 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -7,18 +7,35 @@ * * Contributors: * IBM Corporation - initial API and implementation + * Red Hat, Inc. - Bug #426939 - [validator] HTML5 attribute validator + * marks ng-app AngularJS attributes as undefined *******************************************************************************/ package org.eclipse.wst.html.core.internal.validate; import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.Set; +import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IPreferencesService; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.wst.html.core.internal.HTMLCorePlugin; import org.eclipse.wst.html.core.internal.document.HTMLDocumentTypeConstants; +import org.eclipse.wst.html.core.internal.preferences.HTMLCorePreferenceNames; import org.eclipse.wst.sse.core.internal.provisional.INodeNotifier; import org.eclipse.wst.sse.core.internal.provisional.IndexedRegion; import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; @@ -49,6 +66,9 @@ public class HTMLAttributeValidator extends PrimeValidator { private static final char SINGLE_QUOTE = '\''; private static final char DOUBLE_QUOTE = '\"'; + private IPreferencesService fPreferenceService; + private static Map fIgnorePatterns = new HashMap(); // A storage for ignore patterns (instances of StringMatcher) + // HTML(5) data attributes private static final String ATTR_NAME_DATA = "data-"; //$NON-NLS-1$ private static final int ATTR_NAME_DATA_LENGTH = ATTR_NAME_DATA.length(); @@ -63,6 +83,7 @@ public class HTMLAttributeValidator extends PrimeValidator { */ public HTMLAttributeValidator() { super(); + fPreferenceService = Platform.getPreferencesService(); } /** @@ -153,11 +174,15 @@ public class HTMLAttributeValidator extends PrimeValidator { } if (adec == null) { - if ((attrName.startsWith(ATTR_NAME_DATA) && attrName.length() > ATTR_NAME_DATA_LENGTH) || (attrName.startsWith(ATTR_NAME_USER_AGENT_FEATURE) && attrName.length() > ATTR_NAME_USER_AGENT_FEATURE_LENGTH)) { - DocumentTypeAdapter documentTypeAdapter = (DocumentTypeAdapter) ((INodeNotifier) target.getOwnerDocument()).getAdapterFor(DocumentTypeAdapter.class); - if (documentTypeAdapter != null && documentTypeAdapter.hasFeature(HTMLDocumentTypeConstants.HTML5)) + if ((attrName.startsWith(ATTR_NAME_DATA) && attrName.length() > ATTR_NAME_DATA_LENGTH) || + (attrName.startsWith(ATTR_NAME_USER_AGENT_FEATURE) && attrName.length() > ATTR_NAME_USER_AGENT_FEATURE_LENGTH)) { + if (isHTML5(target)) continue; - } + } + // Check for user-defined exclusions for HTML5 attribute names + if (!shouldValidateAttributeName(target, attrName)) + continue; + // No attr declaration was found. That is, the attr name is // undefined. // but not regard it as undefined name if it includes nested @@ -333,4 +358,60 @@ public class HTMLAttributeValidator extends PrimeValidator { return (c == SINGLE_QUOTE) || (c == DOUBLE_QUOTE); } // D210422 + + private boolean isHTML5(Element target) { + DocumentTypeAdapter documentTypeAdapter = (DocumentTypeAdapter) ((INodeNotifier) target.getOwnerDocument()).getAdapterFor(DocumentTypeAdapter.class); + return (documentTypeAdapter != null && + documentTypeAdapter.hasFeature(HTMLDocumentTypeConstants.HTML5)); + } + + private boolean shouldValidateAttributeName(Element target, String attrName) { + if (!isHTML5(target)) return true; + + Object adapter = (target instanceof IAdaptable ? ((IAdaptable)target).getAdapter(IResource.class) : null); + IProject project = (adapter instanceof IResource ? ((IResource)adapter).getProject() : null); + + Iterator excludedAttributes = getExcludedAttributeNames(project).iterator(); + while (excludedAttributes.hasNext()) { + String excluded = (String)excludedAttributes.next(); + StringMatcher strMatcher = (StringMatcher)fIgnorePatterns.get(excluded); + if (strMatcher == null) { + strMatcher = new StringMatcher(excluded); + fIgnorePatterns.put(excluded, strMatcher); + } + if (strMatcher.match(attrName)) + return false; + } + + return true; + } + + private Set getExcludedAttributeNames(IProject project) { + IScopeContext[] fLookupOrder = new IScopeContext[] {new InstanceScope(), new DefaultScope()}; + if (project != null) { + ProjectScope projectScope = new ProjectScope(project); + if(projectScope.getNode(HTMLCorePlugin.getDefault().getBundle().getSymbolicName()).getBoolean(HTMLCorePreferenceNames.USE_PROJECT_SETTINGS, false)) + fLookupOrder = new IScopeContext[] {projectScope, new InstanceScope(), new DefaultScope()}; + } + + Set result = new HashSet(); + if (fPreferenceService.getBoolean(HTMLCorePlugin.getDefault().getBundle().getSymbolicName(), + HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES, HTMLCorePreferenceNames.IGNORE_ATTRIBUTE_NAMES_DEFAULT, + fLookupOrder)) { + String ignoreList = fPreferenceService.getString(HTMLCorePlugin.getDefault().getBundle().getSymbolicName(), + HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE, HTMLCorePreferenceNames.ATTRIBUTE_NAMES_TO_IGNORE_DEFAULT, + fLookupOrder); + + if (ignoreList.trim().isEmpty()) + return result; + + String[] names = ignoreList.split(","); //$NON-NLS-1$ + for (int i = 0; names != null && i < names.length; i++) { + String name = names[i] == null ? null : names[i].trim(); + if (name != null && !name.isEmpty()) + result.add(name.toLowerCase()); + } + } + return result; + } } |