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.


>
> 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.

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