Package er.coolcomponents

Source Code of er.coolcomponents.CCRating

package er.coolcomponents;

import com.webobjects.appserver.WOActionResults;
import com.webobjects.appserver.WOContext;
import com.webobjects.appserver.WOElement;
import com.webobjects.appserver.WORequest;
import com.webobjects.appserver.WOResponse;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSMutableDictionary;

import er.ajax.AjaxConstantOption;
import er.ajax.AjaxDynamicElement;
import er.ajax.AjaxOption;
import er.ajax.AjaxOptions;
import er.ajax.AjaxUtils;
import er.extensions.appserver.ERXWOContext;


/**
* WebObjects wrapper for LivePipe Rating component, MIT license.
*
* <p>
* CCRating is a fully customizable CSS based ratings widget. By default it acts as an input.  Alternatively, it can notify the
* server when the rating is changed, update the bound value, and call an action method.</p>
*
* <p>It uses four (customizable) CSS class names to determine each link's state:
* <ul>
* <li>rating_off</li>
* <li>rating_half</li>
* <li>rating_on</li>
* <li>rating_selected</li>
* </ul>
* </p>
*
* <p><b>Example Usages</b></p>
*
* <pre>
* Rating: CCRating {
*     value = rating;
* }
* </pre>
* <pre>
* Rating: CCRating {
*     value = rating;
*     actAsInput = false;
* }
* </pre>
* <pre>
* Rating: CCRating {
*     value = rating;
*     actAsInput = false;
*     action = rated;
* }
* </pre>
* <pre>
* Rating: CCRating {
*     value = rating;
*     min = 1;
*     max = 10;
*     multiple = true;
* }
* </pre>
*
* @binding value the value to show in the ratings widget and the value set when the user selects a different rating
* @binding actAsInput optional, default is <code>true</code>, if false updates the value binding when clicked and optionally calls action  method
* @binding action optional, action method to fire when rating changed.  Ignored if actAsInput is <code>true</code> or unbound
* @binding min optional, the value sent to the server when the lowest rating is selected, indirectly controls the number of rating points displayed
* @binding max optional, the value sent to the server when the highest rating is selected, indirectly controls the number of rating points displayed
* @binding multiple optional, <code>true</code> if the user can change a previous rating
* @binding id optional, HTML ID for the div and Control.Rating widget
* @binding capture optional, stops the click event on each rating from propagating
* @binding style optional CSS style for container element
* @binding class optional CSS class for container element in addition to the standard rating_container class
* @binding classNames optional, dictionary of state names and CSS class names with state names of: off, half, on, selected
* @binding rated optional, <code>true</code> if this has already been rated
* @binding reverse optional, <code>true</code> if the links should be shown in reverse order
* @binding updateOptions highly optional, Ajax Options for the request
* @binding formValueName optional, the name of the form value that will contain the value
* @binding elementName optional, defaults to div, the name of the HTML element to use to hold the rating UI
* @binding afterChange, optional, script to run client side after a change e.g. afterChange = "alert(v)";.  Receives one
*              parameter, v, the new value selected
*
* @see <a href="http://livepipe.net/control/rating">Control.Rating</a>
*
* @author chill (WebObjects wrapper only, not LivePipe Rating)
*/
public class CCRating extends AjaxDynamicElement {
 
    public CCRating(String name, NSDictionary associations, WOElement children){
        super(name, associations, children);
    }

    @Override
    protected void addRequiredWebResources(WOResponse response, WOContext context) {
        // Common resources
        addScriptResourceInHead(context, response, "Ajax", "prototype.js");
        addScriptResourceInHead(context, response, "Ajax", "effects.js");
        addScriptResourceInHead(context, response, "Ajax", "controls.js");

        // Library specific resources
        addScriptResourceInHead(context, response, "ERCoolComponents", "Rating/livepipe.js");

        // Component specific resources
        addScriptResourceInHead(context, response, "ERCoolComponents", "Rating/rating.js");
        addStylesheetResourceInHead(context, response, "ERCoolComponents", "Rating/rating.css");
    }


    /**
     * Build div, optional input, and JavaScript into response.
     *
     * @see er.ajax.AjaxDynamicElement#appendToResponse(com.webobjects.appserver.WOResponse, com.webobjects.appserver.WOContext)
     */
    @Override
    public void appendToResponse(WOResponse response, WOContext context) {
        // We don't contain anything, but we need to call super so it calls addRequiredWebResources(WOResponse, WOContext)
        super.appendToResponse(response, context);

        // Build container element like <div id="e_1_0_0_1_3_7" class="rating_container"></div>
       
        String id = id(context);
        String elementName = (String) valueForBinding("elementName", "div", context.component());
        response.appendContentString("<");
        response.appendContentString(elementName);
        response.appendContentString(" ");
        appendTagAttributeToResponse(response, "id", id);
       
        String className = "rating_container";
        if (hasBinding("class")) {
            className += " " + stringValueForBinding("class", context.component());           
        }
        appendTagAttributeToResponse(response, "class", className);

        if (hasBinding("style")) {
            appendTagAttributeToResponse(response, "style", stringValueForBinding("style", context.component()));           
        }
        response.appendContentString("></");
        response.appendContentString(elementName);
        response.appendContentString(">");

        // Build optional input like <input id="e_1_0_0_1_3_7_input" name="e_1_0_0_1_3_7_value" value="5" type="hidden"/>
        if (actAsInput(context)) {
            response.appendContentString("<input ");
            appendTagAttributeToResponse(response, "id", id + "_input");
            appendTagAttributeToResponse(response, "name", formValueName(context));
            appendTagAttributeToResponse(response, "value", valueForBinding("value", context.component()));
            appendTagAttributeToResponse(response, "type", "hidden");
            response.appendContentString("/>");
        }

        // Build script like
        // <script type="text/javascript">
        //     var e_1_0_0_1_3_7 = new Control.Rating('e_1_0_0_1_3_7',
        //         {multiple:true, value:5, min:2, max:8, rated:false, input:'e_1_0_0_1_3_7_input', updateParameterName:'e_1_0_0_1_3_7_value'});
        // </script>
        response.appendContentString("<script type=\"text/javascript\">");
        response.appendContentString("var ");
        response.appendContentString(id);
        response.appendContentString(" = new Control.Rating('");
        response.appendContentString(id);
        response.appendContentString("', ");
        AjaxOptions.appendToResponse(createOptions(context), response, context);
        response.appendContentString("); </script>");
    }

    /**
     * Produce dictionary for options object for Control.Rating.
     *
     * @param context WOContext providing component to resolve bindings in
     * @return binding values converted into Ajax options
     */
    protected NSMutableDictionary createOptions(WOContext context) {
        NSMutableArray ajaxOptionsArray = new NSMutableArray();

        // Standard options from Control.Rating
        ajaxOptionsArray.addObject(new AjaxOption("min", AjaxOption.NUMBER));
        ajaxOptionsArray.addObject(new AjaxOption("max", AjaxOption.NUMBER));
        ajaxOptionsArray.addObject(new AjaxOption("value", AjaxOption.NUMBER));
        ajaxOptionsArray.addObject(new AjaxOption("capture", AjaxOption.BOOLEAN));
        ajaxOptionsArray.addObject(new AjaxOption("classNames", AjaxOption.DICTIONARY));
        ajaxOptionsArray.addObject(new AjaxOption("multiple", AjaxOption.BOOLEAN));
        ajaxOptionsArray.addObject(new AjaxOption("rated", AjaxOption.BOOLEAN));
        ajaxOptionsArray.addObject(new AjaxOption("reverse", AjaxOption.BOOLEAN));
        ajaxOptionsArray.addObject(new AjaxOption("afterChange", AjaxOption.FUNCTION_1));
       
        // updateParameterName is renamed to formValueName to be more WO like
        ajaxOptionsArray.addObject(new AjaxConstantOption("updateParameterName", "formValueName", formValueName(context), AjaxOption.STRING));

        // These parameters are mutually exclusive at present, but dataUpdateUrl could be used with an input if there is a reason for it.
        // I can't think of one right now
        if ( ! actAsInput(context)) {
            ajaxOptionsArray.addObject(new AjaxConstantOption("dataUpdateUrl", AjaxUtils.ajaxComponentActionUrl(context), AjaxOption.STRING));
            ajaxOptionsArray.addObject(new AjaxOption("updateOptions", AjaxOption.DICTIONARY));
        }
        else {
            ajaxOptionsArray.addObject(new AjaxConstantOption("input", id(context) + "_input", AjaxOption.STRING));
        }

        return AjaxOption.createAjaxOptionsDictionary(ajaxOptionsArray, context.component(), associations());
    }

    /**
     * Handles server action if this is not being use as an input.  Sets the value binding and calls the optional action method.
     *
     * @see er.ajax.AjaxDynamicElement#handleRequest(com.webobjects.appserver.WORequest, com.webobjects.appserver.WOContext)
     * @see #takeValuesFromRequest(WORequest, WOContext)
     *
     * @return null, this component returns nothing to the client
     */
    @Override
    public WOActionResults handleRequest(WORequest request, WOContext context) {
        setValueFromFormValue(request, context);

       // Nothing gets returned to the client from  the CCRating action so we discard any result from firing the action binding
       if (hasBinding("action")) {
           valueForBinding("action", context.component());
       }

        return null;
    }

    /**
     * Sets value binding if this is being used as an input.
     *
     * @see er.ajax.AjaxDynamicElement#takeValuesFromRequest(com.webobjects.appserver.WORequest, com.webobjects.appserver.WOContext)
     * @see #handleRequest(WORequest, WOContext)
     */
    @Override
    public void takeValuesFromRequest(WORequest request, WOContext context) {
        if (actAsInput(context)) {
            setValueFromFormValue(request, context);
        }
        super.takeValuesFromRequest(request, context);
    }

    /**
     * Sets the value binding based on the form value.
     *
     * @see #takeValuesFromRequest(WORequest, WOContext)
     * @see #handleRequest(WORequest, WOContext)
     *
     * @param request the WORequest to get the form values from
     * @param context WOContext used to determine component used in
     */
    protected void setValueFromFormValue(WORequest request, WOContext context) {
        Object ratingValue = request.formValueForKey(formValueName(context));
        if (ratingValue instanceof String) {
            ratingValue = Integer.valueOf((String)ratingValue);
        }
        setValueForBinding(ratingValue, "value", context.component());
    }

    /**
     * @param context WOContext used to determine component used in
     * @return optional value for formValueName, or calculated value if unbound
     */
    protected String formValueName(WOContext context) {
        return (String)valueForBinding("formValueName", id(context) + "_value", context.component());
    }

    /**
     * @param context WOContext used to determine component used in
     * @return optional value for id, or calculated value if unbound
     */
    @Override
    public String id(WOContext context) {
        return (String) valueForBinding("id", ERXWOContext.safeIdentifierName(context, false), context.component());
    }

    /**
     * @param context WOContext used to determine component used in
     * @return optional value for actAsInput, or <code>true</code> if unbound
     */
    protected boolean actAsInput(WOContext context) {
        return booleanValueForBinding("actAsInput", true, context.component());
    }
}
TOP

Related Classes of er.coolcomponents.CCRating

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.