DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Coding
  3. Frameworks
  4. Tapestry and 'Editable for Bootstrap'

Tapestry and 'Editable for Bootstrap'

Taha Siddiqi user avatar by
Taha Siddiqi
·
Dec. 04, 12 · Interview
Like (0)
Save
Tweet
Share
3.22K Views

Join the DZone community and get the full member experience.

Join For Free

 Twitter Bootstrap is a relief to programmers like me who were never good at web-designing. It has a nice javascript library and there are already modules to integrate twitter-bootstrap with tapestry. There are a lot of good add ons coming up for bootstrap and one of my favourites is the Editable for Bootstrap. Every time I see such a library I wait for a oppurtunity to integrate it with Tapestry.

To use this library you don’t have to do much. Even the ajax part is handled for you. So you just have to handle the server-side stuff and return success status or a failure message. As there are a few of these components, we can start with a base component and then extend it for each component.

@SupportsInformalParameters
@Import(
    library = {
        "classpath:bootstrap-editable/js/bootstrap-editable.js",
        "classpath:pines/jquery.pnotify.js"
    },
    stylesheet = {
        "classpath:bootstrap-editable/css/bootstrap-editable.css",
        "classpath:pines/jquery.pnotify.default.css"
    }
)
public abstract class AbstractBootstrapEditable implements ClientElement {

    @Parameter(value = "prop:componentResources.id", defaultPrefix = BindingConstants.LITERAL, allowNull = false)
    private String client;

    @Parameter(autoconnect = true, required = true)
    private Object value;

    @Parameter
    private Object[] context;

    @Parameter
    private boolean disabled;

    private String assignedClientId;

    @Inject
    private JavaScriptSupport javaScriptSupport;

    @Inject
    private ComponentResources resources;

    @Inject
    private Request request;

    @Inject
    private TypeCoercer typeCoercer;

    @BeginRender
    void begin(MarkupWriter writer) {
        assignedClientId = javaScriptSupport.allocateClientId(resources);

        if (disabled) {
            writer.element("span");
        } else {
            Element element = writer.element("span",
                "id", getClientId(),
                "data-name", getClientId(),
                "data-url", getPostbackLink());

            contributeDataParams(element);
        }

        resources.renderInformalParameters(writer);
    }

    protected void contributeDataParams(Element element) {

    }

    @AfterRender
    void after(MarkupWriter writer) {
        writer.end();

        if (!disabled) {
            javaScriptSupport.addScript(
                "jQuery('#%s').editable({" +
                    "success:function(data){ " +
                    "if(!data.success){return data.msg; }else return null;}" +
                    "});",
                getClientId());
        }
    }

    private String getPostbackLink() {
        return resources.createEventLink("postback", context).toAbsoluteURI();
    }

    @SuppressWarnings("unchecked")
    @OnEvent("postback")
    Object submit(@RequestParameter("value") String value, EventContext context) {
        this.value = toValue(value);
        CaptureResultCallback<String> callback = new CaptureResultCallback<String>();
        boolean handled = resources.triggerContextEvent(EventConstants.SUBMIT, context, callback);

        JSONObject result = new JSONObject();

        if (handled) {
            String response = callback.getResult();
            if (response != null) {
                result.put("success", false);
                result.put("msg", response);
                return result;
            }
        }

        return result.put("success", true);
    }

    protected abstract Object toValue(String value);

    @Override
    public String getClientId() {
        return assignedClientId;
    }
}


The data-url is set to the server-side callback and will be called for updation. The callback delegates the updation to the SUBMIT event along with the context. The value is passed to the parameter of the same name.

A text field will be as simple as

public class Text extends AbstractBootstrapEditable {

    @Override
    protected void contributeDataParams(Element element){
        element.attribute("data-type", "text");
    }

    @Override
    protected Object toValue(String value) {
        return value;
    }

}

and a textarea field will be

public class TextArea extends AbstractBootstrapEditable {

    @Override
    protected void contributeDataParams(Element element) {
        element.attribute("data-type", "textarea");
    }

    @Override
    protected Object toValue(String value) {
        return value;
    }

}

Select will be a bit more code as you will need a SelectModel and a ValueEncoder

public class Select extends AbstractBootstrapEditable {

    @Parameter(required = true, allowNull = false)
    private SelectModel model;

    @Parameter(required = true, allowNull = false)
    private ValueEncoder encoder;

    @Inject
    private ComponentResources resources;

    @Inject
    private ComponentDefaultProvider defaultProvider;

    @SuppressWarnings("unchecked")
    ValueEncoder defaultEncoder() {
        return defaultProvider.defaultValueEncoder("value", resources);
    }

    @SuppressWarnings("unchecked")
    SelectModel defaultModel() {
        Class valueType = resources.getBoundType("value");

        if (valueType == null)
            return null;

        if (Enum.class.isAssignableFrom(valueType))
            return new EnumSelectModel(valueType, resources.getContainerMessages());

        return null;
    }

    @Override
    protected void contributeDataParams(Element element) {
        element.attribute("data-type", "select");
        element.attribute("data-source", getSource());
    }

    @SuppressWarnings("unchecked")
    public String getSource() {
        JSONObject source = new JSONObject();

        for (OptionModel option : model.getOptions()) {
            source.put(encoder.toClient(option.getValue()), option.getLabel());
        }

        return source.toCompactString();
    }

    @Override
    protected Object toValue(String value) {
        return encoder.toValue(value);
    }

}


Usage

Just implement the onSubmit() event and return null for success and a failure message in case of a failure.. That is all!





Bootstrap (front-end framework)

Published at DZone with permission of Taha Siddiqi, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Do Not Forget About Testing!
  • Implementing Infinite Scroll in jOOQ
  • Cloud Native London Meetup: 3 Pitfalls Everyone Should Avoid With Cloud Data
  • DevSecOps Benefits and Challenges

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: