/**
* 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.basic;
import fiftyfive.wicket.util.Shortcuts;
import org.apache.wicket.markup.ComponentTag;
import org.apache.wicket.markup.MarkupStream;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.Model;
/**
* An extension of Wicket's Label component that allows a placeholder value to
* be specified. If the label's default model is empty, then:
* <ul>
* <li>A CSS class of "empty" will be added to the tag</li>
* <li>The placeholder value (if one is specified) will be emitted as the
* body of the tag</li>
* </ul>
* <p>
* If the model is not empty, this behaves like the standard Label.
* <p>
* Example usage:
* <pre class="example">
* <span wicket:id="label">Sample</span>
*
* IModel<String> emptyModel = null;
* add(new LabelWithPlaceholder("label", emptyModel).setPlaceholder("N/A"));</pre>
* <p>
* Since the model in this example is null, the placeholder will be used,
* resulting in this output:
* <pre class="example">
* <span class="empty">N/A</span></pre>
* <p>
* Notice also that {@code class="empty"} has been added.
*
* @see #setPlaceholder
* @see Label
* @since 2.0
*/
public class LabelWithPlaceholder extends Label
{
private IModel<?> placeholderValue;
/**
* @see Label#Label(String)
*/
public LabelWithPlaceholder(final String id)
{
this(id, (IModel) null);
}
/**
* @see Label#Label(String, String)
*/
public LabelWithPlaceholder(final String id, String label)
{
this(id, new Model(label));
}
/**
* @see Label#Label(String, IModel)
*/
public LabelWithPlaceholder(final String id, IModel<?> model)
{
super(id, model);
add(Shortcuts.cssClass(Shortcuts.prop(this, "cssClass")));
}
/**
* Returns "empty" if the value provided by this label's model is empty.
* Otherwise returns {@code null}.
*/
public String getCssClass()
{
return isEmpty() ? "empty" : null;
}
/**
* Sets the value that will be used if the value provided by the
* model is empty.
* Note that this value will be escaped based on the label's
* {@link Label#getEscapeModelStrings() getEscapeModelStrings()} flag.
*/
public LabelWithPlaceholder setPlaceholder(String valueIfEmpty)
{
return setPlaceholder(Model.of(valueIfEmpty));
}
/**
* Sets the value that will be used if the value provided by the label's
* normal model is empty. For localization, consider passing in an
* instance of Wicket's StringResourceModel.
* Note that this value will be escaped based on the label's
* {@link Label#getEscapeModelStrings() getEscapeModelStrings()} flag.
*/
public LabelWithPlaceholder setPlaceholder(IModel<?> valueIfEmpty)
{
this.placeholderValue = valueIfEmpty;
return this;
}
/**
* Returns <code>true</code> if the model of this label is empty.
* @see Shortcuts#empty
*/
public boolean isEmpty()
{
return Shortcuts.empty(internalGetDefaultModelObjectAsString());
}
/**
* Detaches the model that holds the placeholder value.
*/
@Override
protected void onDetach()
{
if(null != this.placeholderValue) this.placeholderValue.detach();
super.onDetach();
}
/**
* Renders the label using the string value of the model as the tag body.
* If the value of the model is empty and placeholder was provided by
* {@link #setPlaceholder}, use the placeholder instead.
* @see Shortcuts#empty
*/
@Override
public void onComponentTagBody(MarkupStream markupStream,
ComponentTag openTag)
{
String str = internalGetDefaultModelObjectAsString();
if(this.placeholderValue != null && Shortcuts.empty(str))
{
str = getDefaultModelObjectAsString(this.placeholderValue.getObject());
}
replaceComponentTagBody(markupStream, openTag, str);
}
/**
* A wrapper for {@link #getDefaultModelObjectAsString()} that can be
* overridden by subclasses.
*/
protected String internalGetDefaultModelObjectAsString()
{
return getDefaultModelObjectAsString();
}
}