On Wed, Jul 31, 2013 at 3:04 PM, Martin Grigorov <mgrigo...@apache.org>wrote:

> Hi Sebastien,
>
>
> On Wed, Jul 31, 2013 at 2:37 PM, Sebastien <seb...@gmail.com> wrote:
>
>> Hi,
>>
>> I agree with Igor. Just have to take care that binding to document is not
>> a
>> default behavior for all bound events, and that it should be use with
>> care.
>>
>
> I think Igor said the opposite - bind on document with child selector:
> $(document).on('click', '[data-w-click]', handler);
>
>
>> (IMHO, the javadoc should be enough)
>> Martin, I unfortunately did not had the chance to have a look at your code
>> now... :s But, if it not the case, if think EventDelegatingBehavior should
>> have a constructor that take a component (the datatable for instance) as
>> an
>>
>
> Behavior#bind(Component) gives you a reference to the component. No need
> to pass it as ctor parameter.
>
>
>> argument so the event can be bound it it instead of the document (by
>> getting its markupid as the selector)...
>
>
>> [quote]
>> Here is another important tips "*Attaching many delegated event handlers
>> near the top of the document tree can degrade performance*". For best
>> performance, attach delegated events at a document location as close as
>> possible to the target elements as done in above jQuery code
>> [/quote]
>>
>>
>> http://jquerybyexample.blogspot.com/2013/04/direct-vs-delegated-events-with-jquery-on-method.html
>
>
> According to this article it is better to bind on the table than on the
> document.
> At least this is how I read it.
>
>
>>
>>
>>
>> I think events delegation would be a great addition anyhow...
>>
>> Best regards,
>> Sebastien.
>>
>>
> From the discussion so far I see these two issues which need to be solved
> before starting make changes in the code:
>
> 1) it must be possible to use event delegation on "the table", not only on
> the document
> 2) if the ajax attributes are stored in data-w-eventName attribute on the
> element then we need to figure out where to store the Ajax call listeners'
> functions
>

<input type="text" wicket:id="ac" size="50" value="" name="ac" id="ac2"
autocomplete="off"
data-w-change="{&quot;f&quot;:&quot;form1&quot;,&quot;u&quot;:&quot;./autocomplete?1-1.IBehaviorListener.1-form-ac&quot;,&quot;e&quot;:&quot;change&quot;,&quot;m&quot;:&quot;POST&quot;}"/>

At the moment the value for data-w-eventName It is not very readable...


>
>
> For 1) I see it as a new Ajax request attribute - bindOnComponent = true
> If the attribute is 'false' then the event will be bound on the document
> instead and will use event delegation.
> This way all <td>s can return false, and the <table> can return true to
> handle the bubbling event (and stop it, because otherwise it will be
> handled twice when the event reaches the document)
>
> For 2) We can introduce global registry (e.g.
> Wicket.Ajax.Handlers[markupId][handlerType] =>
> Wicket.Ajax.Handlers["someId12"]["success"] = function(...) {...}).
> So the "global" handler (bound on the table or on the document) can use
> the specific Ajax call listeners for the clicked element with attribute
> 'data-w-eventName'
>
> WDYT ?
>
>
>
>>
>>
>> On Tue, Jul 30, 2013 at 7:07 PM, Igor Vaynberg <igor.vaynb...@gmail.com
>> >wrote:
>>
>> > binding on document is fine, you just have to make sure your code is
>> fast
>> > in case you are binding to things like mousemove.
>> >
>> > -igor
>> >
>> >
>> > On Tue, Jul 30, 2013 at 1:31 AM, Martin Grigorov <mgrigo...@apache.org
>> > >wrote:
>> >
>> > > On Fri, Jul 12, 2013 at 5:21 PM, Igor Vaynberg <
>> igor.vaynb...@gmail.com
>> > > >wrote:
>> > >
>> > > > On Fri, Jul 12, 2013 at 1:50 AM, Martin Grigorov <
>> mgrigo...@apache.org
>> > >
>> > > > wrote:
>> > > > > On Fri, Jul 12, 2013 at 8:59 AM, Igor Vaynberg <
>> > > igor.vaynb...@gmail.com
>> > > > >wrote:
>> > > > >
>> > > > >> On Thu, Jul 11, 2013 at 7:22 AM, Martin Grigorov <
>> > > mgrigo...@apache.org>
>> > > > >> wrote:
>> > > > >> > On Thu, Jul 11, 2013 at 4:48 PM, Sven Meier <s...@meiers.net>
>> > > wrote:
>> > > > >> >
>> > > > >> >> Hi,
>> > > > >> >>
>> > > > >> >>
>> > > > >> >> >The idea with plain JS solution I cannot visualize in my head
>> > yet.
>> > > > >> >>
>> > > > >> >> EventDelegatingBehavior is just a collector of JavaScript
>> > snippets.
>> > > > The
>> > > > >> >> actual magic runs in the browser: a custom bubbling of events
>> and
>> > > > >> >> delegation to the actual behavior.
>> > > > >> >> It should be possible to do this plain with JavaScript:
>> > > > >> >>
>> > > > >> >>   public class DelegatingAjax implements IAjax {
>> > > > >> >>
>> > > > >> >>     public ajax(IHeaderResponse response, Component component,
>> > > > >> >> AjaxRequestAttributes attributes) {
>> > > > >> >>       CharSequence ajaxAttributes =
>> > > renderAjaxAttributes(**component,
>> > > > >> >> attributes);
>> > > > >> >>
>> > > > >> >>
>> > > > >>
>> > > >
>> > >
>> >
>> response.render(**OnDomReadyHeaderItem.**forScript("Wicket.Event.***delegate*("
>> > > > >> >> + ajaxAttributes + ");");
>> > > > >> >>     }
>> > > > >> >>   }
>> > > > >> >>
>> > > > >> >> This would be page-global though.
>> > > > >> >
>> > > > >> >
>> > > > >> > This is an important detail!
>> > > > >> > I'll consult with my frontend colleagues but so far I don't see
>> > > > problems.
>> > > > >> >
>> > > > >> > For every delegated component we can set special CSS class,
>> e.g.
>> > > > >> > 'wicket-delegated'.
>> > > > >> > The binding will be: $(document).on('click',
>> '.wicket-delegated',
>> > > > >> > function(event) {....})
>> > > > >> > i.e. we will take advantage of jQuery delegation/live support.
>> > > > >> > This way even newly added items in the repeaters will be
>> > > automatically
>> > > > >> > supported.
>> > > > >>
>> > > > >>
>> > > > >> this is partially on the right track, but there are still some
>> > > > >> optimization that can be made.
>> > > > >>
>> > > > >> first, the ajax attributes need to be moved into a data attribute
>> > that
>> > > > >> is written out on the tag. the final output of attaching a
>> onclick
>> > > > >> ajax behavior to a tag should end up looking like this:
>> > > > >>
>> > > > >> <a wicket:id="ajaxlink"
>> > > > >> data-w-click="u/?0.foo:bar.ILinkListener/c/default/pd/true"/>
>> > > > >>
>> > > > >> (we will need to figure out how to encode ajax attributes into a
>> > > string)
>> > > > >>
>> > > > >
>> > > > > example:
>> > > > > <a id="c23" data-w-attrs='{"u":"someUrl","m":"post"}' ...>
>> > > > >
>> > > > > $('#c23').data("w-attrs") === {u: "someUrl", m: "post"}
>> > > > >
>> > > > > This works for valid JSON, but it doesn't for the enhancement we
>> use
>> > -
>> > > > the
>> > > > > functions for the call listeners.
>> > > >
>> > > > i did say we need to figure out a way to encode it right above the
>> > > example
>> > > > :)
>> > > >
>> > > > >> then you can have the one global listener:
>> > > > >>
>> > > > >> $(document).on("click", function(e) {
>> > > > >>
>> > > > >
>> > > > > The problem here is that using 'document' will make the things
>> > actually
>> > > > > slower.
>> > > > > We need to find a simple way to be able to bind on a parent
>> > component.
>> > > > > In Sven's example - a table with many cells the most appropriate
>> > > element
>> > > > is
>> > > > > the <table> itself.
>> > > >
>> > > > umm, why does it make things slower exactly? this has virtually no
>> > > > overhead, events bubble up anyways...so where does the slowness come
>> > > > from?
>> > > >
>> > >
>> > > All the talks about the deprecation of jQuery#live() say that binding
>> on
>> > > the document is not a good idea (performance wise).
>> > >
>> > > If it is not possible to bind on a context element then I see no much
>> > > benefit.
>> > >
>> > >
>> > > >
>> > > > -igor
>> > > >
>> > > > >
>> > > > > In event-delegating-behavior branch I need to traverse the parent
>> > > > > components and their behaviors to be able to find the appropriate
>> > > parent.
>> > > > > So we win some performance in JS execution but lose some in Java
>> :-/
>> > > > >
>> > > > >    var element=$(this), attrs=element.attr("data-w-click");
>> > > > >>    if (attrs&&!e.handledByWicket)
>> > > > >>        Wicket.Ajax.call(attrs);
>> > > > >>        e.handledByWicket=true; // if there are more handlers
>> above,
>> > do
>> > > > >> not double process the event - read below
>> > > > >>    }
>> > > > >> }
>> > > > >>
>> > > > >> the advantage here is that we only have one javascript listener
>> that
>> > > > >> needs to be registered.
>> > > > >>
>> > > > >> however, there are a few disadvantages:
>> > > > >> * event propagation options wont work anymore, because the event
>> has
>> > > > >> to propagate all the way to the document in order to trigger.
>> > > > >> * some libraries block events. for example if there is a panel
>> with
>> > an
>> > > > >> ajax link inside a third party modal window. the modal window lib
>> > may
>> > > > >> prevent any clicks from propagating out of itself, which means
>> the
>> > > > >> handler on the document will never see them.
>> > > > >>
>> > > > >> we can sort of solve this by having a behavior that would write
>> out
>> > > > >> the listener above, but attached to the component not the
>> document.
>> > > > >>
>> > > > >> that way, if we look at my example with the panel inside the
>> modal,
>> > > > >> the user can add this behavior to the panel that will be in the
>> > modal
>> > > > >> and still be able to capture the event.
>> > > > >>
>> > > > >> this does, however, make troubleshooting more difficult. why
>> didnt
>> > my
>> > > > >> ajax event trigger? you will have to be a lot more aware about
>> what
>> > > > >> javascript you have in the dom.
>> > > > >
>> > > > >
>> > > > >> i think a short term goal might be to move the ajax attributes
>> into
>> > a
>> > > > >> dom attribute and change our ajax code to simply say
>> > > > >> Wicket.Ajax.bind("click", "component234");
>> > > > >>
>> > > > >
>> > > > > see above (valid JSON)
>> > > > >
>> > > > > we can enrich the DOM:
>> > > > > <a ... onsuccess="someScript">
>> > > > > but I think this is a step back to Wicket 1.5 days (ajax
>> decorators
>> > on
>> > > > > strings, etc.)
>> > > > >
>> > > > >
>> > > > >>
>> > > > >> this will register the listener like above on the element
>> directly.
>> > so
>> > > > >> no delegation yet but cleaner javascript/html. also the browser
>> > doesnt
>> > > > >> have to parse as much javascript, so it will be a bit speedier.
>> > > > >>
>> > > > >> potentially we can collect ids to further optimize js size:
>> > > > >> Wicket.Ajax.bind({click, ["c34", "c32"], blur: ["c22","c98"]);
>> > > > >>
>> > > > >> -igor
>> > > > >>
>> > > > >>
>> > > > >> >
>> > > > >> >
>> > > > >> >>
>> > > > >> >>
>> > > > >> >> Sven
>> > > > >> >>
>> > > > >> >>
>> > > > >> >>
>> > > > >> >> On 07/11/2013 03:40 PM, Martin Grigorov wrote:
>> > > > >> >>
>> > > > >> >>> On Thu, Jul 11, 2013 at 4:30 PM, Nick Pratt <
>> nbpr...@gmail.com>
>> > > > wrote:
>> > > > >> >>>
>> > > > >> >>>  I think this is great - we have some tables now with a ton
>> of
>> > JS
>> > > > >> events
>> > > > >> >>>> on
>> > > > >> >>>> the child elements.  Just to clarify, will this make the
>> > rendered
>> > > > page
>> > > > >> >>>> smaller since there will only be a single JS handler for the
>> > > event
>> > > > for
>> > > > >> >>>> the
>> > > > >> >>>> container rather than N JS handlers?
>> > > > >> >>>>
>> > > > >> >>>>  At the moment all attributes for an inner element are
>> > preserved.
>> > > > >> >>> 'e' (the event name), 'c' (the component markup id), pd
>> (prevent
>> > > > >> default),
>> > > > >> >>> sp (stop propagation) can be removed because they are not
>> really
>> > > > used.
>> > > > >> >>> But every inner element can have its own call listeners, form
>> > > > >> submitters
>> > > > >> >>> can also have custom settings ('f', 'sc', 'mp', 'm'), so I
>> think
>> > > > they
>> > > > >> have
>> > > > >> >>> to be preserved.
>> > > > >> >>> If you look in #updateAjaxAttributes() for your ajax
>> behaviors
>> > in
>> > > > your
>> > > > >> >>> table cells you will probably notice that they have their own
>> > > > >> attributes.
>> > > > >> >>>
>> > > > >> >>>
>> > > > >> >>>  Making it switchable (I think how Sven suggested) would be
>> an
>> > > > >> >>>> improvement -
>> > > > >> >>>> we could leave it off by default, but provide a simple
>> switch
>> > on
>> > > a
>> > > > >> >>>> per-container (or per-app) basis that would allow the dev to
>> > > > choose.
>> > > > >> >>>>
>> > > > >> >>>>  Yes, it looks as an improvement.
>> > > > >> >>> Moving the current code to such implementation is easy.
>> > > > >> >>> The idea with plain JS solution I cannot visualize in my head
>> > yet.
>> > > > >> >>>
>> > > > >> >>>
>> > > > >> >>>  Regards
>> > > > >> >>>>
>> > > > >> >>>> Nick
>> > > > >> >>>>
>> > > > >> >>>> On Thu, Jul 11, 2013 at 4:59 AM, Martin Grigorov <
>> > > > >> mgrigo...@apache.org
>> > > > >> >>>>
>> > > > >> >>>>> wrote:
>> > > > >> >>>>> Hi,
>> > > > >> >>>>>
>> > > > >> >>>>> At https://github.com/apache/**wicket/compare/event-**
>> > > > >> >>>>> delegating-behavioryou<
>> > > > >>
>> > https://github.com/apache/wicket/compare/event-delegating-behavioryou
>> > > >
>> > > > >> >>>>> may see the diff between master and
>> event-delegating-behavior
>> > > > >> branches.
>> > > > >> >>>>>
>> > > > >> >>>>> The latter provides a new AjaxEventBehavior (AEB) -
>> > > > >> >>>>>
>> > > > >> >>>> EventDelegatingBehavior
>> > > > >> >>>>
>> > > > >> >>>>> (EDB), that suppresses the JS event binding for all
>> > > > >> AjaxEventBehaviors
>> > > > >> >>>>>
>> > > > >> >>>> for
>> > > > >> >>>>
>> > > > >> >>>>> a given event type (click, submit, change, ...) in the
>> > children
>> > > > >> >>>>>
>> > > > >> >>>> components
>> > > > >> >>>>
>> > > > >> >>>>> of the host component of EDB.
>> > > > >> >>>>>
>> > > > >> >>>>> How EDB works:
>> > > > >> >>>>>
>> > > > >> >>>>> - until now AjaxEventBehavior#renderHead() renders
>> ondomready
>> > > > header
>> > > > >> >>>>> item
>> > > > >> >>>>> with JS snippet like:
>> > > > >> >>>>> Wicket.Ajax.ajax(**attributesObject);
>> > > > >> >>>>> In the new branch there is a check if some parent has EDB
>> for
>> > > the
>> > > > >> event
>> > > > >> >>>>> type of this AEB, and if there is such then the AEB
>> "donates"
>> > > its
>> > > > >> >>>>> attributes to the EDB.
>> > > > >> >>>>>
>> > > > >> >>>>> - EventDelegatingBehavior#**getCallbackScript() renders :
>> > > > >> >>>>> Wicket.Event.delegate('**edbComponentMarkupId',
>> 'eventType',
>> > > > >> >>>>> edbAttributes,
>> > > > >> >>>>> childrenAttrsMap);
>> > > > >> >>>>>
>> > > > >> >>>>> - when a delegated component fires its event (e.g. the user
>> > > clicks
>> > > > >> on an
>> > > > >> >>>>> AjaxLink) the event is handled by EDB's event handler. It
>> > > extracts
>> > > > >> the
>> > > > >> >>>>> markupId of the inner HTML element and fires
>> Wicket.Ajax.Call
>> > > with
>> > > > >> the
>> > > > >> >>>>> specific attributes for the extracted inner element.
>> > > > >> >>>>>
>> > > > >> >>>>> Pros:
>> > > > >> >>>>>
>> > > > >> >>>>> - simple to use - just add EDB to a container component
>> around
>> > > > your
>> > > > >> Ajax
>> > > > >> >>>>> heavy component (e.g. repeater with many Ajax behaviors).
>> See
>> > > the
>> > > > >> demo
>> > > > >> >>>>>
>> > > > >> >>>> app
>> > > > >> >>>>
>> > > > >> >>>>> at https://issues.apache.org/**jira/browse/WICKET-5267<
>> > > > >> https://issues.apache.org/jira/browse/WICKET-5267>
>> > > > >> >>>>>
>> > > > >> >>>>> -  faster JS execution
>> > > > >> >>>>> -- faster execution of the domready handler because there
>> is
>> > > just
>> > > > one
>> > > > >> >>>>> binding instead of N
>> > > > >> >>>>> -- faster reaction because the browser finds the event
>> handler
>> > > > much
>> > > > >> >>>>>
>> > > > >> >>>> faster.
>> > > > >> >>>>
>> > > > >> >>>>> I wasn't able to prove this with numbers because there is
>> no
>> > way
>> > > > to
>> > > > >> >>>>>
>> > > > >> >>>> detect
>> > > > >> >>>>
>> > > > >> >>>>> the 'start time', i.e. when the user makes the action.
>> With JS
>> > > the
>> > > > >> >>>>>
>> > > > >> >>>> earliest
>> > > > >> >>>>
>> > > > >> >>>>> point is when the browser has already looked up the event
>> > > handler.
>> > > > >> >>>>> Chrome Dev tools (timeline, profiling, pagespeed) don't
>> help
>> > > too.
>> > > > So
>> > > > >> my
>> > > > >> >>>>> reference that it is faster are the articles in the web
>> and a
>> > > use
>> > > > >> case
>> > > > >> >>>>> in
>> > > > >> >>>>> our application.
>> > > > >> >>>>>
>> > > > >> >>>>> Cons:
>> > > > >> >>>>>
>> > > > >> >>>>> - AEB#renderHead() needs to check whether there is EDB up
>> in
>> > the
>> > > > >> >>>>>
>> > > > >> >>>> hierarchy
>> > > > >> >>>>
>> > > > >> >>>>> to be able to decide what to do.
>> > > > >> >>>>> This is ugly, I agree. But I see no other solution that
>> will
>> > > > preserve
>> > > > >> >>>>> the
>> > > > >> >>>>> transparent usage of something like EDB and will not
>> require a
>> > > > major
>> > > > >> >>>>> rewrite of user applications to be able to use event
>> > delegation.
>> > > > >> >>>>> -- there are some optimizations to lower the impact of the
>> new
>> > > > >> checks:
>> > > > >> >>>>> --- a new setting (IAjaxSettings#**useEventDelegation) - a
>> > > global
>> > > > >> >>>>> property
>> > > > >> >>>>> that prevents visiting the parent components and their
>> > behaviors
>> > > > for
>> > > > >> all
>> > > > >> >>>>> apps which do not use EDB
>> > > > >> >>>>> --- when EDB is bound it registers a metadata for its event
>> > type
>> > > > in
>> > > > >> the
>> > > > >> >>>>> page instance. This prevents visiting all behaviors of all
>> > > parent
>> > > > >> >>>>> components
>> > > > >> >>>>>
>> > > > >> >>>>>
>> > > > >> >>>>> I have no more ideas how to further optimize it.
>> > > > >> >>>>>
>> > > > >> >>>>> Any feedback is welcome! Even if you have a completely
>> > different
>> > > > idea
>> > > > >> >>>>> how
>> > > > >> >>>>> to implement this functionality.
>> > > > >> >>>>>
>> > > > >> >>>>> Thanks for reading!
>> > > > >> >>>>>
>> > > > >> >>>>>
>> > > > >> >>
>> > > > >>
>> > > >
>> > >
>> >
>>
>
>

Reply via email to