Skip to content

Instantly share code, notes, and snippets.

@sody
Created September 30, 2011 07:32
Show Gist options
  • Save sody/1252973 to your computer and use it in GitHub Desktop.
Save sody/1252973 to your computer and use it in GitHub Desktop.
package com.example.components;
import com.example.internal.CSSConstants;
import org.apache.tapestry5.BindingConstants;
import org.apache.tapestry5.MarkupWriter;
import org.apache.tapestry5.MarkupWriterAdapter;
import org.apache.tapestry5.MarkupWriterListener;
import org.apache.tapestry5.annotations.AfterRender;
import org.apache.tapestry5.annotations.BeginRender;
import org.apache.tapestry5.annotations.Parameter;
import org.apache.tapestry5.dom.Element;
import org.apache.tapestry5.dom.Node;
import org.apache.tapestry5.dom.Text;
/**
* Corresponds to jquery.ui button widgets. It is responsible for correct button rendering with all needed content and
* styles that will prevent content flashing during applying styles on client-side. This component should enclose other
* HTML elements(e.g links, buttons, radios, checkboxes, etc.) that are candidates to be a client-side jquery.ui
* buttons. Foe example:
* <pre>
* &lt;t:button primary="ui-icon-plus"&gt;
* &lt;t:eventlink event="add"&gt;Add&lt;/t:eventlink&gt;
* &lt;/t:button&gt;
* &lt;t:button&gt;&lt;t:submit/&gt;&lt;/t:button&gt;
* &lt;t:button secondary="ui-icon-triangle-1-s"&gt;
* &lt;a href="#"&gt;Menu&lt;/a&gt;
* &lt;/t:button&gt;
* </pre>
*
* @author Ivan Khalopik
* @tapestrydoc
* @since 1.0
*/
public class Button {
private static final String EMPTY_TEXT_PLACEHOLDER = "_EMPTY_";
private static final String[][][] BUTTON_TYPES = {
{
{CSSConstants.BUTTON_TEXT_ONLY, CSSConstants.BUTTON_ICON_ONLY},
{CSSConstants.BUTTON_ICON_ONLY, CSSConstants.BUTTON_ICONS_ONLY}
},
{
{CSSConstants.BUTTON_TEXT_ONLY, CSSConstants.BUTTON_TEXT_ICON_SECONDARY},
{CSSConstants.BUTTON_TEXT_ICON_PRIMARY, CSSConstants.BUTTON_TEXT_ICONS}
}
};
/**
* Class name applied to button element in addition to usual button styles.
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL, name = "class")
private String className;
/**
* Primary icon to be added to button.
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String primary;
/**
* Secondary icon to be added to button.
*/
@Parameter(defaultPrefix = BindingConstants.LITERAL)
private String secondary;
private final MarkupWriterListener listener = new MarkupWriterAdapter() {
@Override
public void elementDidEnd(final Element element) {
processElement(element);
}
};
/**
* Adds markup writer listener that processes child markup with {@link #processElement(org.apache.tapestry5.dom.Element)}
* method.
*
* @param writer markup writer, not {@code null}
*/
@BeginRender
void beginRender(final MarkupWriter writer) {
writer.addListener(listener);
}
/**
* Removes markup writer listener after render component.
*
* @param writer markup writer, not {@code null}
*/
@AfterRender
void afterRender(final MarkupWriter writer) {
writer.removeListener(listener);
}
/**
* Processes every child element inside this component with applying all necessary styles and adding all needed
* content.
*
* @param element element to process, not {@code null}
*/
private void processElement(final Element element) {
// get element name
final String elementName = element.getName();
// input elements processing differs from others
if (elementName.equals("input")) {
// get input type
final String type = element.getAttribute("type");
if (type != null && type.equals("submit")) {
// submit buttons can have only styles
addButtonStyle(element);
} else {
// other input types should be hided
// all styles will be applied to their label elements
element.addClassName(CSSConstants.HELPER_HIDDEN_ACCESSIBLE);
}
} else {
// other elements will have all needed styles and all necessary content
addButtonStyle(element);
addButtonContent(element);
}
}
/**
* Adds special ui button styles to specified element.
*
* @param element element to add styles for, not {@code null}
*/
private void addButtonStyle(final Element element) {
// add specified class if bounded
if (className != null) {
element.addClassName(className);
}
// add usual button styles
element.addClassName(
CSSConstants.BUTTON,
CSSConstants.WIDGET,
CSSConstants.STATE_DEFAULT,
CSSConstants.CORNER_ALL);
}
/**
* Adds generated content to specified element. It includes button type class, label, primary and secondary items.
* NOTE: It should not be applied to input elements, only for their labels.
*
* @param button button to generate content for, not {@code null}
*/
private void addButtonContent(final Element button) {
// get label element
Element label = getText(button);
// determine button type according to hasText, hasPrimaryIcon, hasSecondaryIcon options
final String buttonType = BUTTON_TYPES[label != null ? 1 : 0][primary != null ? 1 : 0][secondary != null ? 1 : 0];
// add button type to class attribute
button.addClassName(buttonType);
// if label is not found, create empty placeholder
if (label == null) {
label = button.element("span");
label.text(EMPTY_TEXT_PLACEHOLDER);
}
label.addClassName(CSSConstants.BUTTON_TEXT);
// add span for primary icon
if (primary != null) {
button.element("span")
.addClassName(CSSConstants.BUTTON_ICON_PRIMARY, CSSConstants.ICON, primary)
.moveBefore(label);
}
// add span for secondary icon
if (secondary != null) {
button.element("span")
.addClassName(CSSConstants.BUTTON_ICON_SECONDARY, CSSConstants.ICON, secondary)
.moveAfter(label);
}
}
/**
* Looks for text node inside the specified element and wraps it with {@code 'span'} element.
*
* @param button element to find text for, not {@code null}
* @return {@code 'span'} wrapper element around founded text or {@code null} if not found
*/
private Element getText(final Element button) {
for (Node node : button.getChildren()) {
if (node instanceof Text) {
// return wrapped with span text
return node.wrap("span");
}
}
return null;
}
}
T5.extendInitializer({
"jquery.ui": function() {
(function($) {
// create buttons from every element of 'ui-button' class
$(".ui-button").each(function() {
// get element
var element = $(this);
// find element representing primary icon ang parse it's class attribute
var primary = element.find(".ui-button-icon-primary")
.removeClass("ui-button-icon-primary ui-button-icon-secondary ui-icon")
.attr("class");
// find element representing secondary icon ang parse it's class attribute
var secondary = element.find(".ui-button-icon-secondary")
.removeClass("ui-button-icon-primary ui-button-icon-secondary ui-icon")
.attr("class");
// find element representing button text and get it's content
var label = element.find(".ui-button-text").html();
// '_EMPTY_' means that button doesn't have any text
var text = label && label != "_EMPTY_";
// if element is label we should create button from input it references for
if (element.is("label")) {
element = $("#" + element.attr("for"));
}
// create button
element.button({
text: text,
label: label,
icons: {
primary: primary,
secondary: secondary
}
});
});
})(jQuery);
}
});
<div id="buttons">
<button>A button element</button>
<input type="submit" value="A submit button"/>
<a href="#">An anchor</a>
</div>
<script type="text/javascript">
(function($) {
$(document).ready(function() {
$("input:submit, a, button", "#buttons").button();
});
})(jQuery);
</script>
<a class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only" href="#">
<span class="ui-button-text">Link</span>
</a>
<button class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
<span class="ui-button-text">Button</span>
</button>
<input class="ui-button ui-widget ui-state-default ui-corner-all" value="Submit" type="submit"/>
<script type="text/javascript">
(function($) {
$(document).ready(function() {
setTimeout(function() {
$("input:submit, a, button", "#buttons").button();
}, 1500);
});
})(jQuery);
</script>
<t:actionlink class="ui-button ui-widget ui-state-default ui-corner-all ui-button-text-only">
<span class="ui-button-text">Action Link</span>
</t:actionlink>
<t:button primary="ui-icon-plus">
<a href="#">Link</a>
</t:button>
<t:button secondary="ui-icon-triangle-1-s">
<t:actionlink>Action Link</t:actionlink>
</t:button>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment