Tks Joost,

I will read  then more later tell about your components.




2010/5/1 Joost Schouten (ml) <joost...@jsportal.com>

> Hi Pablo,
>
> This all can be achieved with Mixins.
>
> For the autocomplete-select I add my own ForceAutocomplete Mixin (which
> extends Autocomplete)  to a TextField. I have my ForceAutocomplete add a
> link (downward arrow img) behind the input which will trigger the
> "autocomplete" event. In stead of passing the textfield value, I pass a
> static identifier indicating this is a call from the link allowing the
> Tapestry providecompletions event to return full list, or whatever other
> requirements you might have.
>
> I've posted some code here below. I apologize where it might be slightly
> unclear as I have not yet had the time to refactor so it is clear and clean.
> A fair bit of code is also in place to cater for the
> FORCE_AUTOCOMPLETE_ON_CHANGE which is triggered when a user selects an item
> from the list to allow for another list of options to be shown. We use this
> for selections where you need to drill down to a deeper child.
>
> As for the drag and drop; this one is quite easy. Though we have the code
> embedded in our calendar component, it's quite easy to write a mixin that
> take a handleDomId and a dropableDomId (or whatever other droppable method
> you wish to use) and have it create the appropriate javascript. In the
> Draggable.onEnd() method you can have it trigger an ajax call with an T5
> event identifier, so that your Tapestry component can respond appropriately
> if needed.
>
> I hope this is not too unclear and can help you a little bit in getting
> started. Don't focus too much on our code I would say but just get started
> with your own mixin.
>
> Cheers,
> Joost
>
>
> [1]:
> ForceAutocomplete
> @IncludeJavaScriptLibrary("ForceAutocomplete.js")
> @IncludeStylesheet("ForceAutocomplete.css")
> public class ForceAutocomplete extends Autocomplete{
>     public static final String NAME_ID_DEVIDER = "_NID_";
>     public static final String DOM_ID_ITEM_ID_DEVIDER = "_DIIID_";
>
>   public static final String FORCE_AUTOCOMPLETE_ON_CLICK =
> "FORCE_AUTOCOMPLETE_ON_CLICK";
>     public static final String FORCE_AUTOCOMPLETE_ON_CHANGE =
> "FORCE_AUTOCOMPLETE_ON_CHANGE";
>     public static final String OPTIONS_DEVIDER_END = " ----";
>
>   public static final String OPTIONS_DEVIDER_START = "---- ";
>
>   @Parameter(value = "prop:componentResources.id", defaultPrefix =
> "literal")
>   private String clientId;
>     @Parameter(required = false, defaultPrefix = "literal")
>   private String idFieldClass;
>     @Inject
>   private RenderSupport renderSupport;
>     @Inject
>   private ComponentResources resources;
>     @Persist
>   private String autocompleteFieldId;
>     /**
>    * setting this to true will force an autocomplete call to be fired on
> every change
>    */
>   @Parameter(required = true, defaultPrefix = "literal")
>   private boolean addOnchangeCall;
>     @Inject
>   @Path("drop_down_arrow.gif")
>   private Asset dropdownArrow;
>     @Inject
>   @Path("context:/static/images/themes/jsportal/loader.gif")
>   private Asset jsLoaderImage;
>     private String loaderId;
>       @AfterRender
>   private void after(MarkupWriter writer) {
>       Element container = writer.getElement();
>       Element autoCompField = null;
>       for(Node node : container.getChildren()) {
>           if(node instanceof Element) {
>               Element el = (Element) node;
>               if(el.getName().toLowerCase().equals("input") &&
>                       el.getAttribute("type").equals("text")) {
>                   autoCompField = el;
>                   break;
>               }
>           }
>       }
>       autoCompField.addClassName("forceAutocompleteField");
>       autocompleteFieldId = autoCompField.getAttribute("id");
>             loaderId = autocompleteFieldId + ":js_loader";
>             Element forceAutocompleteFieldContainer = writer.element("div",
>               "class",
>               "forceAutocompleteFieldContainer");
>       writer.end();
>             autoCompField.moveToBottom(forceAutocompleteFieldContainer);
>             forceAutocompleteFieldContainer.element("img",
>               "src", jsLoaderImage.toClientURL(),
>               "class", "t-autoloader-icon " + CSSClassConstants.INVISIBLE,
>               "id", loaderId);
>             String handleId = autocompleteFieldId + ":handle_anchor";
>       Element handleAnchor = forceAutocompleteFieldContainer.element("a",
>               "class", "handleAnchor",
>               "id", handleId);
>       handleAnchor.element("img",
>               "class", "forceAutocompleteHandler",
>               "src", dropdownArrow.toClientURL());
>             StringBuffer script = new StringBuffer();
>       script.append("$T('" + autocompleteFieldId + "').forceAutocompleter =
> new ForceAutocomplete($('" + autocompleteFieldId + "'), '" +
> getAutocompleteUrl() + "', " + addOnchangeCall);
>       if(idFieldClass != null) {
>           script.append(", '" + idFieldClass + "'");
>       }
>             script.append(");");
>             renderSupport.addScript(script.toString());
>   }
>     protected void configure(JSONObject config){
>       config.remove("indicator");
>       config.put("indicator", loaderId);
>   }
>     public String getAutocompleteUrl() {
>       return
> resources.getContainerResources().createEventLink("autocomplete").toAbsoluteURI();
>   }
>     /**
>    * Overwrites the Autocomplete method to add a title to each li
>    */
>   @Override
>   protected void generateResponseMarkup(MarkupWriter writer, List matches){
>       writer.element("ul");
>
>       for (Object o : matches){
>           String name = o.toString();
>                               Element li = writer.element("li",
>                   "title", name);
>
> if(name.indexOf(ForceAutocomplete.OPTIONS_DEVIDER_START) != -1 &&
>                   name.indexOf(ForceAutocomplete.OPTIONS_DEVIDER_END) !=
> -1) {
>               li.addClassName("devider");
>           }
>           writer.write(name);
>           writer.end();
>       }
>
>       writer.end(); // ul
>   }
>
> }
>
>
> ForceAutocomplete.js:
>
> Ajax.Autocompleter.addMethods({
>   onBlur: function() {
>       fa = $T(this.element).forceAutocompleter;
>       fa.inputFocus = false;
>       fa.onBlurSelectorItem();
>   }
> });
>
> var FORCE_AUTOCOMPLETE_CHANGED_EVENT =
> 'joostschouten:FORCE_AUTOCOMPLETE_CHANGED_EVENT';
>
> function ForceAutocomplete (elem, ajaxUrl, includeChange, idFieldClass) {
>   this.elem = elem;
>   $T(this.elem).forceAutocompleter = this;
>   this.hideTimeoutIndex = null;
>   this.ajaxUrl = ajaxUrl;
>   this.includeChange = includeChange;
>   this.forceAutocompleteFieldContainer =
> this.elem.up('.forceAutocompleteFieldContainer');
>   this.handle = this.forceAutocompleteFieldContainer.down('.handleAnchor');
>   this.lastSelected = null;
>   this.selectedIdField = null;
>   if(idFieldClass) {
>       this.selectedIdField =
> this.forceAutocompleteFieldContainer.previous('.' + idFieldClass);
>       this.lastSelected = this.selectedIdField.value;
>   }
>   this.handle.observe('click',
> this.handleForcedUpdate.bindAsEventListener(this));
>   this.elem.observe('focus', this.onInputFocus.bindAsEventListener(this));
>   //this.elem.observe('keydown',
> this.handleKeyDown.bindAsEventListener(this));
>
> window.setTimeout(this.registerNewOnCompleteMethod.bindAsEventListener(this),
> 5);
> }
>
> ForceAutocomplete.prototype = {
>   registerNewOnCompleteMethod : function () {
>       this.autocompleter = $T(this.elem).autocompleter;
>       if(this.autocompleter) {
>           //stop observing the blur eveny on the AutoComplete
>           this.autocompleter.onBlur =
> this.onBlurSelectorItem.bindAsEventListener(this);
>                     this.autocompleter.options.onComplete =
> this.onComplete.bindAsEventListener(this);
>           this.autocompleter.options.onHide =
> this.onHide.bindAsEventListener(this);
>           this.autocompleter.options.onShow =
> this.onShow.bindAsEventListener(this);
>       }
>       else {
>
> window.setTimeout(this.registerNewOnCompleteMethod.bindAsEventListener(this),
> 100);
>       }
>   },
>   onHide : function () {
>       this.autocompleter.update.hide();
>   },
>   onShow : function () {
>       update = this.autocompleter.update;
>       if(!update.style.position || update.style.position=='absolute') {
>         update.style.position = 'absolute';
>         Position.clone(this.elem, update, {
>           setHeight: false,
>           offsetTop: this.elem.offsetHeight
>         });
>       }
>       update.show();
>   },
>   onComplete : function (transport) {
>             var autoCompleter = $T(this.elem).autocompleter;
>       autoCompleter.changed = false;
>       autoCompleter.hasFocus = true;
>       autoCompleter.active = true;
>
>       autoCompleter.update.update(transport.responseText);
>       lis = autoCompleter.update.down().childElements();
>                   if(lis.length>0) {
>           valueMatchesOption = false;
>           for(i = 0;i<lis.length;i++) {
>               if(!valueMatchesOption && lis[i].innerHTML ==
> this.elem.value) {
>                   valueMatchesOption = true;
>               }
>               if(lis[i].innerHTML != this.elem.value &&
> !lis[i].hasClassName('devider')) {
>                   lis[i].observe('click',
> this.handleForcedUpdateFromChange.bindAsEventListener(this));
>               }
>           }
>                     if(!valueMatchesOption && this.selectedIdField != null)
> {
>               //set the selected value to null as the option does not exist
>               this.selectedIdField.value = '';
>           }
>                     if(lis.length == 1 && lis[0].innerHTML ==
> this.elem.value) {
>               // if there is one exact match, set it and don't show
> suggestions
>               this.loadValueFromItem(lis[0]);
>           }
>           else {
>               //focus on the input field so that the update list will not
> be hidden
>               this.elem.focus();
>               autoCompleter.show();
>           }
>       }
>       else {
>           autoCompleter.hide();
>       }
>       autoCompleter.stopIndicator();
>   },
>   onCompleteFromChange : function (transport) {
>       this.onComplete(transport);
>       this.elem.fire(FORCE_AUTOCOMPLETE_CHANGED_EVENT);
>   },
>   handleForcedUpdate : function(event) {
>       var autoCompleter = $T(this.elem).autocompleter;
>             //focus on the input field so that the update list will not be
> hidden
>       this.elem.focus();
>                   actionName = 'FORCE_AUTOCOMPLETE_ON_CLICK_' +
> this.elem.value;
>             if(this.lastSelected != null) {
>           actionName = actionName + '_NID_' + this.lastSelected;
>       }
>             //in case when the list is already showing, hide it when
> clicked
>       if(autoCompleter.update.visible()) {
>           autoCompleter.update.hide();
>       }
>       else {
>           autoCompleter.startIndicator();
>           event.stop();
>           var myAjax = new Ajax.Request( this.ajaxUrl , {method: 'post',
> parameters: 't:input=' + actionName, onSuccess:
> this.onComplete.bindAsEventListener(this)} );
>             }
>   },
>   handleForcedUpdateFromChange : function (event) {          li =
> Event.findElement(event, 'LI');
>       this.loadValueFromItem(li);
>   },
>   loadValueFromItem : function(li) {
>             liCont = li.innerHTML;
>       if(li.hasClassName('devider')) {
>           return false;
>       }
>             if(this.elem.value != liCont) {
>           this.elem.value = liCont;
>       }
>             //set the value to the content of the li
>       if(this.includeChange) {
>           $T(this.elem).autocompleter.startIndicator();
>           passValue = liCont;
>           //strip of the DOM id before passing
>           if(li.id && li.id != null) {
>               itemId = li.id;
>               if(itemId.indexOf('_DIIID_') != -1) {
>                   itemId = itemId.split('_DIIID_')[1];
>               }
>               passValue = passValue + '_NID_' + itemId;
>           }
>           tokens =  passValue.split('_')
>           this.lastSelected = tokens[tokens.length-1];
>           actionName = 'FORCE_AUTOCOMPLETE_ON_CHANGE_' + passValue;
>           var myAjax = new Ajax.Request( this.ajaxUrl , {method: 'post',
> parameters: 't:input=' + actionName, onSuccess:
> this.onCompleteFromChange.bindAsEventListener(this)} );
>       }
>   },
>   /**
>    * called by each item of the selector. Checks to see if any field of the
> selector is
>    * focus'ed if so, don't hide the options, if not, hide
>    */
>   onBlurSelectorItem:function(event) {
>       autoComp = $T(this.elem).autocompleter;
>       this.hideTimeoutIndex = setTimeout(autoComp.hide.bind(autoComp),
> 250);
>       this.hasFocus = false;
>       this.active = false;
>   },
>   onInputFocus:function() {
>       if(this.hideTimeoutIndex != null) {
>           clearTimeout(this.hideTimeoutIndex);
>
>       }
>   }
> }
>
> Pablo dos Reis wrote:
>
>> Joost,
>>
>> I liked the video very much.
>> If you can pass at least the idea of components I thank.
>> How was it implemented? What javascript was use?
>> The code would bee good too.
>>
>>
>> And I think interesting you post here for all users can see.
>>
>>
>>
>> tks
>>
>> 2010/4/30 Joost Schouten (ml) <joost...@jsportal.com>
>>
>>
>>
>>> Pablo,
>>>
>>> If interested we have created a full drag and drop calendar and select
>>> with
>>> auto-complete for our internal project. I could share some of our code to
>>> give you a head start. The product is not yet launched but these these
>>> features are partly shown in this video [1]
>>>
>>> Let me know if you would like to have a look
>>>
>>> Cheers,
>>> Joost
>>>
>>> [1]:http://www.youtube.com/watch?v=_GVW0JvkDkg
>>>
>>>
>>> Pablo dos Reis wrote:
>>>
>>>
>>>
>>>> Tks everybody
>>>>
>>>> Now I am studing about Scriptaculous
>>>> I already create a wiki
>>>> http://wiki.apache.org/general/PabloGSOC2010
>>>>
>>>> I accept sugestions for it
>>>>
>>>> Soon I' ll post my doubts here.
>>>>
>>>>
>>>>
>>>> 2010/4/28 Charith Madusanka <charithc...@gmail.com>
>>>>
>>>>
>>>>
>>>>
>>>>
>>>>> Hi Pablo,
>>>>>
>>>>> Congratulations and Good luck...............!!!
>>>>>
>>>>> Charith
>>>>>
>>>>> On Thu, Apr 29, 2010 at 5:05 AM, Thiago H. de Paula Figueiredo <
>>>>> thiag...@gmail.com> wrote:
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> On Wed, 28 Apr 2010 20:01:23 -0300, Pablo dos Reis <
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>> pablodosr...@gmail.com>
>>>>>
>>>>>
>>>>>
>>>>>
>>>>>> wrote:
>>>>>>
>>>>>>  There are ohters students working in tapestry project through GSOC?
>>>>>>     You're the only one with an approved proposal.
>>>>>>
>>>>>> --
>>>>>> Thiago H. de Paula Figueiredo
>>>>>> Independent Java, Apache Tapestry 5 and Hibernate consultant,
>>>>>> developer,
>>>>>> and instructor
>>>>>> Owner, Ars Machina Tecnologia da Informação Ltda.
>>>>>> http://www.arsmachina.com.br
>>>>>>
>>>>>> ---------------------------------------------------------------------
>>>>>> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
>>>>>> For additional commands, e-mail: users-h...@tapestry.apache.org
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>
>>>>
>>>>
>>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
>>> For additional commands, e-mail: users-h...@tapestry.apache.org
>>>
>>>
>>>
>>>
>>
>>
>>
>>
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscr...@tapestry.apache.org
> For additional commands, e-mail: users-h...@tapestry.apache.org
>
>


-- 
Pablo Henrique dos Reis

Reply via email to