content: /**
   * Copyright 2014 55 Minutes (http://www.55minutes.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 fiftyfive.wicket.css;
  
  import java.util.Arrays;
  import java.util.LinkedHashSet;
  import java.util.Set;
  import org.apache.wicket.Component;
  import org.apache.wicket.behavior.Behavior;
  import org.apache.wicket.markup.ComponentTag;
  import org.apache.wicket.markup.parser.XmlTag.TagType;
  import org.apache.wicket.util.string.Strings;
  
  
  /**
   * A behavior simliar to {@link org.apache.wicket.AttributeModifier AttributeModifier} but
   * specially tuned for modifying the HTML {@code class} attribute. When this behavior is bound
   * to a component it does the following:
   * <ul>
   * <li>Always adds the {@code class} attribute, even if it did not already exist.</li>
   * <li>Ensures that duplicate CSS classes will not be emitted in the attribute.</li>
   * <li>Each class will be separated by a space character.</li>
   * </ul>
   * Note that this class is abstract. Subclasses must implement the
   * {@link #modifyClasses modifyClasses()} to specify what classes are added (or subtracted!)
   * from the {@code class} attribute.
   * 
   * @since 2.0.4
   * @see fiftyfive.wicket.util.Shortcuts#toggledCssClass(String,org.apache.wicket.model.IModel)
   */
  public abstract class CssClassModifier extends Behavior
  {
      /**
       * Implemented by subclasses to specify what CSS classes should be added or subtracted
       * to the HTML for this component.
       * 
       * @param component The component whose HTML element is being rendered.
       * 
       * @param cssClasses A set containing all the CSS classes that were declared in the markup
       *                   for this component, if any. If values are added to this set, they will
       *                   be emitted in the {@code class} attribute of the element when the
       *                   component renders, with a space separating each value. Values may also
       *                   be removed in order to prevent them from being emitted.
       */
      protected abstract void modifyClasses(Component component, Set<String> cssClasses);
  
      /**
       * Parse any existing classes declared in the markup for this component and then delegate
       * to {@link #modifyClasses modifyClasses()}. Set resulting set of classes on the component
       * tag to render its {@code class} attribute with the desired values.
       */
      @Override
      public void onComponentTag(Component component, ComponentTag tag)
      {
          if(tag.getType() != TagType.CLOSE)
          {
              Set<String> values = new LinkedHashSet<String>();
              String existing = tag.getAttribute("class");
              if(existing != null)
              {
                  values.addAll(Arrays.asList(existing.split("\\s+")));
              }
              modifyClasses(component, values);
              tag.put("class", Strings.join(" ", values.toArray(new String[0])));
          }
      }
  }
  