com.helger.css.tools.MediaQueryTools Maven / Gradle / Ivy
/**
* Copyright (C) 2014-2016 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* 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.helger.css.tools;
import java.util.List;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.Nonempty;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.collection.CollectionHelper;
import com.helger.commons.string.StringHelper;
import com.helger.css.ECSSVersion;
import com.helger.css.decl.CSSImportRule;
import com.helger.css.decl.CSSMediaQuery;
import com.helger.css.decl.CSSMediaRule;
import com.helger.css.decl.CSSNamespaceRule;
import com.helger.css.decl.CascadingStyleSheet;
import com.helger.css.decl.ICSSTopLevelRule;
import com.helger.css.reader.CSSReader;
/**
* A small utility class to wrap an existing {@link CascadingStyleSheet} within
* a specific media, if possible. {@link CascadingStyleSheet} can only be
* wrapped, if they don't contain a media rule themselves.
*
* @author Philip Helger
*/
@Immutable
public final class MediaQueryTools
{
@SuppressWarnings ("unused")
@PresentForCodeCoverage
private static final MediaQueryTools s_aInstance = new MediaQueryTools ();
private MediaQueryTools ()
{}
/**
* Utility method to convert a media query string to a structured list of
* {@link CSSMediaQuery} objects.
*
* @param sMediaQuery
* The media query string to parse. May be null
.
* @param eVersion
* The CSS version to use. May not be null
.
* @return null
if the passed media query is null
or
* empty or not parsable.
*/
@Nullable
public static List parseToMediaQuery (@Nullable final String sMediaQuery,
@Nonnull final ECSSVersion eVersion)
{
if (StringHelper.hasNoText (sMediaQuery))
return null;
final String sCSS = "@media " + sMediaQuery + " {}";
final CascadingStyleSheet aCSS = CSSReader.readFromString (sCSS, eVersion);
if (aCSS == null)
return null;
final CSSMediaRule aMediaRule = aCSS.getAllMediaRules ().get (0);
return aMediaRule.getAllMediaQueries ();
}
/**
* Check if the passed CSS can be wrapped in an external media rule.
*
* @param aCSS
* The CSS to be checked for wrapping. May be null
.
* @param bAllowNestedMediaQueries
* if true
nested media queries are allowed,
* false
if they are prohibited.
* @return true
if the CSS can be wrapped, false
if
* it can't be wrapped.
*/
public static boolean canWrapInMediaQuery (@Nullable final CascadingStyleSheet aCSS,
final boolean bAllowNestedMediaQueries)
{
if (aCSS == null)
return false;
if (bAllowNestedMediaQueries)
return true;
// Nested media queries are not allowed, therefore wrapping can only take
// place if no other media queries are present
return !aCSS.hasMediaRules ();
}
/**
* Get the CSS wrapped in the specified media query. Note: all existing rule
* objects are reused, so modifying them also modifies the original CSS!
*
* @param aCSS
* The CSS to be wrapped. May not be null
.
* @param aMediaQuery
* The media query to use.
* @param bAllowNestedMediaQueries
* if true
nested media queries are allowed,
* false
if they are prohibited.
* @return null
if out CSS cannot be wrapped, the newly created
* {@link CascadingStyleSheet} object otherwise.
*/
@Nullable
public static CascadingStyleSheet getWrappedInMediaQuery (@Nonnull final CascadingStyleSheet aCSS,
@Nonnull final CSSMediaQuery aMediaQuery,
final boolean bAllowNestedMediaQueries)
{
return getWrappedInMediaQuery (aCSS, CollectionHelper.newList (aMediaQuery), bAllowNestedMediaQueries);
}
/**
* Get the CSS wrapped in the specified media query. Note: all existing rule
* objects are reused, so modifying them also modifies the original CSS!
*
* @param aCSS
* The CSS to be wrapped. May not be null
.
* @param aMediaQueries
* The media queries to use. May neither be null
nor empty
* nor may it contain null
elements.
* @param bAllowNestedMediaQueries
* if true
nested media queries are allowed,
* false
if they are prohibited.
* @return null
if out CSS cannot be wrapped, the newly created
* {@link CascadingStyleSheet} object otherwise.
*/
@Nullable
public static CascadingStyleSheet getWrappedInMediaQuery (@Nonnull final CascadingStyleSheet aCSS,
@Nonnull @Nonempty final Iterable extends CSSMediaQuery> aMediaQueries,
final boolean bAllowNestedMediaQueries)
{
ValueEnforcer.notNull (aCSS, "CSS");
ValueEnforcer.notEmpty (aMediaQueries, "MediaQueries");
if (!canWrapInMediaQuery (aCSS, bAllowNestedMediaQueries))
return null;
final CascadingStyleSheet ret = new CascadingStyleSheet ();
// Copy all import rules
for (final CSSImportRule aImportRule : aCSS.getAllImportRules ())
{
if (aImportRule.hasMediaQueries ())
{
// import rule already has a media query - do not alter
ret.addImportRule (aImportRule);
}
else
{
// Create a new rule and add the passed media queries
final CSSImportRule aNewImportRule = new CSSImportRule (aImportRule.getLocation ());
for (final CSSMediaQuery aMediaQuery : aMediaQueries)
aNewImportRule.addMediaQuery (aMediaQuery);
ret.addImportRule (aNewImportRule);
}
}
// Copy all namespace rules
for (final CSSNamespaceRule aNamespaceRule : aCSS.getAllNamespaceRules ())
ret.addNamespaceRule (aNamespaceRule);
// Create a single top-level media rule ...
// into this media rule
final CSSMediaRule aNewMediaRule = new CSSMediaRule ();
for (final CSSMediaQuery aMediaQuery : aMediaQueries)
aNewMediaRule.addMediaQuery (aMediaQuery);
// ... and add the existing top-level rules into this media rule
for (final ICSSTopLevelRule aRule : aCSS.getAllRules ())
aNewMediaRule.addRule (aRule);
// Finally add the resulting media rule into the new CSS
ret.addRule (aNewMediaRule);
return ret;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy