1 2 3 4 Previous Next 129 Replies Latest reply on Nov 7, 2013 2:30 AM by blabno Go to original post
      • 15. Re: Schedule
        blabno

        Hi Nick, as you have seen in demo you have written, widget can accept callback functions on event selection, day selection, event moving or resizing. Same as navigating between dates. We just have to provide functions that will do ajax in the richfaces style.

         

        Target object seems to be more appropriate. Will this introduce any problems?

        I think not at all, since widget will send eventId as request param and UISchedule can fetch target object from datamodel during broadcast.

        Should we generate standalone listener tags? I don't get the idea why it is not an attribute in tree.

        • 16. Re: Schedule
          nbelaevski

          widget can accept callback functions on event selection, day selection, event moving or resizing. Same as navigating between dates. We just have to provide functions that will do ajax in the richfaces style.

          So a question is whether this should be built-in and each action (e.g. date selection) should fire Ajax request, or it will require explicit addition of a4j:support. I prefer the second variant.

           

          Should we generate standalone listener tags? I don't get the idea why it is not an attribute in tree.

          There's an attribute, but nested tags complement this the same as for h:commandLink you can use "actionListener" attribute together with nested f:actionListener tags.

          • 17. Re: Schedule
            blabno
            it will require explicit addition of a4j:support. I prefer the second variant.

            How do we send additional data, like dayDelta or eventId when we attach a4j:support?

            I guess a4j:jsFunction would have to be used and wrapped by user's function that would be a callback for widget. This will decrease reuse, for the same functionality will have to be repeated for each schedule tag on the page and in each project.

            • 18. Re: Schedule
              nbelaevski

              It can be encapsulated in form inputs, so that a4j:support component will submit their values to the server together with the whole form. Then schedule component will decode them as usual. And a4j:jsFunction can be used either as a4j:support.

              • 19. Re: Schedule
                blabno

                Ok, so javascript updates inputs on client side on item resizing, moving and selecting.

                Now, dev adds <a4j:support action="#{bean.itemSelected}"/> but how should that method know which item was selected? It is the component that should do the decoding. Should component have attributes like "selectedItem", "dayDelta", "minuteDelta" that could be bound to "bean" ?

                 

                I think we should just have those modes "ajax", "client", "server". If you are working in "ajax" mode then all listeners are fired during ajax request. If you are working in "server" mode then every clicking, resizing, moving will cause form submit (this mode would probably be just for displaying, and very rarely used). If you work in "client" mode then attaching listeners would be cause exception. This way devs will have ease of use (just define swithType instead of attaching a4j:support).

                 

                Edited one day later:

                There is also other attitude. Resizing, editing and selecting by default works only on client side. If dev wants backing beans to be updated on server side, he should attach a4j:support. I consider it a poor solution.

                 

                Other question is how do jboss-el works? i.e.: #{bean.itemSelected(item)}. Cause devs would like it most to attach <a4j:support action="#{bean.itemSelected(item)}". Should UISchedule set selected index on data model during broadcast? If so then should it be done with setRowIndex or setRowKey? Anyway those methods are used by JSF to iterate over datamodel. What is the guarantee that selection made during broadcast (apply request values phase i guess) will remain the same until invokeApplication or other time when a4j:support will execute action?

                • 20. Re: Schedule
                  nbelaevski

                  There is also other attitude. Resizing, editing and selecting by default works only on client side. If dev wants backing beans to be updated on server side, he should attach a4j:support. I consider it a poor solution.

                  Ok, let's use set of built-in modes as you've proposed. External a4j:support is really a poor solution for this case.

                  • 21. Re: Schedule
                    blabno

                    I'm having problems component caching data. The "date" attribute is bound to managed bean property via EL. I submit form that updates that property, but cached "_date" attribute is cached on UISchedule. When shall I clear it, or should it be done automatically?

                    • 22. Re: Schedule
                      nbelaevski

                      It should be cleared after ValueExpression has been updated successfully: see javax.faces.component.UIInput.updateModel(FacesContext) for example.

                      • 23. Re: Schedule
                        blabno

                        Time for demo: http://bernard.labno.pl/schedule-sample

                         

                        Nick, problem from last post was due to my implementation. Sorry for false alarm.

                         

                        Questions:

                        1. How about merging events data in broadcast method sent back on ScheduleLoadEvent (fired on displayed date range change) with data requested by user "<rich:schedule data="tralalala"/>
                        2. Please look at UISchedule src (getCalendarData method) and guide me with data model visitor. I don't know what process method should do.
                        3. There are two options for navigation between dates. Which do we choose :
                          1. fire event and force developer to provide event listener that will change data model
                          2. check if data model is ExtendedDataModel and send DateRange (new, custom implementation of Range) - current implementation
                        4. If we go with option 3.2 then should we still fire DateRangeChangedEvent?
                        5. Should getItemMovedListener method from UISchedule return MethodBinding or MethodExpression?
                        6. When should we fire listeners from getFacesListeners()? After reading JSF2 specs I guess that it should be before firing method expression bound to xxxListener (i.e. itemMovedListener) attribute. In which phase should such events be fired?
                        7. Currently all event listeners are declared as properties of component (itemMovedListener, itemSelectedListener) which allows only one listener per each event to be registered. Should we allow more listeners to be registered? If so then how, via some custom tag or is there other solution?
                        8. Sending xxEvent object to listener methods binds them tightly to RichFaces. I'm wondering if we couldn't make it different so that backing beans wouldn't have to rely on RichFaces api.
                        9. I have already created 5 events for item moved, item resized, item selected, schedule load, view changed. Isn't this too much? I think not.
                        10. Which name do you prefer ScheduleLoadEvent or DateRangeChangedEvent?
                        11. How should parsing exceptions in decode method be handled? Packed into RuntimeException and rethrown, logged as warnings?
                        12. What's the difference between using scopeChain variables and object properties (i.e this.id) - check richfaces.fullcalendar.js

                         

                        Last thing, I've run into frustrating problem in Webkit (safari,chrome) based browsers. If content type is set to application/xhtml+xml then some DOM modifications just won't work (i.e. div.innerHTML=" " will work from page, but not if it is located in external js file). This artilce http://j4fry.blogspot.com/2009/06/jsf-20-and-dojo-create.html suggest to apply listener that would change the content type, but we cannot force people to do that to get our component working. Here is the link to issue in webkit bugtracker, it doesn't seem they are going to fix it. What shall we do? This is very, very old bug of webkit.

                         

                        TODO: http://docs.google.com/View?id=dfhnwkfw_9hf76sff9

                        • 24. Re: Schedule
                          nbelaevski

                          Hi Bernard,

                           

                          First of all, let me excuse for the delay in replying, 4.0 work took all my time last week.

                          How about merging events data in broadcast method sent back on ScheduleLoadEvent (fired on displayed date range change) with data requested by user "<rich:schedule data="tralalala"/>

                          IMO, users expect passed data to be available as "data" variable in "oncomplete", not smth. like "data.realData". So we can do the following:

                           

                          ajaxContext.getResponseDataMap().put("_ajax:scheduleData", dataObject);
                          
                          

                          and read serialized data on the client side via:

                          req.getJSON('_ajax:scheduleData')
                          

                          Please look at UISchedule src (getCalendarData method) and guide me with data model visitor. I don't know what process method should do.

                          Data model works in the following way:

                           

                          1. Model client invokes walk(...) method passing in callback method that will be called for each item in the model (this method is the only method declared in DataVisitor interface), desired range to walk through and arbitrary object to pass invocation context to DataVisitor.

                          2. Model implementation walks through the requested range, generating model item keys and passing them into DataVisitor#process.

                          3. Inside DataVisitor#process setRowKey() is called using passed key, establishing iteration context (updating request variables). After that it can read current model item data via getRowData() method.

                           

                          Very basic example of DataVisitor usage for encoding component is org.ajax4jsf.renderkit.html.RepeatRenderer class.

                           

                          So, instead of explicitly iterating through model items using "for" cycle, you can move all that handling into process method. BTW, we usually setup variables via ExternalContext#getRequestMap(), and this doesn't require creation of ValueExpression.

                           

                          1. fire event and force developer to provide event listener that will change data model
                          2. check if data model is ExtendedDataModel and send DateRange (new, custom implementation of Range) - current implementation

                          I like #2.

                          If we go with option 3.2 then should we still fire DateRangeChangedEvent?

                          Yes, it's useful for application developers.

                          Should getItemMovedListener method from UISchedule return MethodBinding or MethodExpression?

                          We can do the same as in EditableValueHolder: there is getter/setter for MethodBinding and MethodExpression is assigned via ValueChangeListener wrapper. BTW, MethodBinding is also stored as FacesListener wrapper.

                          When should we fire listeners from getFacesListeners()? After reading JSF2 specs I guess that it should be before firing method expression bound to xxxListener (i.e. itemMovedListener) attribute. In which phase should such events be fired?

                          broadcast() in UIComponentBase calls listeners returned from getFacesListeners(), so if you wrap MethodExpression into FacesListener as I suggested before, the order of calls will be correct. Event phase depends on what event is for: is it more like ValueChangeEvent or ActionEvent. I'm going to check what events are doing and post my thoughts on phases.

                          Currently all event listeners are declared as properties of component (itemMovedListener, itemSelectedListener) which allows only one listener per each event to be registered. Should we allow more listeners to be registered? If so then how, via some custom tag or is there other solution?

                          Yes, registration of set of listeners is necessary, but can be implemented later. Custom tags are created for this, you can check tree component CDK confguration file: http://anonsvn.jboss.org/repos/richfaces/branches/community/3.3.X/ui/tree/src/main/config/component/commonTreeListeners.ent

                          Sending xxEvent object to listener methods binds them tightly to RichFaces. I'm wondering if we couldn't make it different so that backing beans wouldn't have to rely on RichFaces api.

                          Seam provides ExpressionFactory that allows to omit event argument in listener method signature (e.g. use processAction() instead of processAction(ActionEvent)) transparently to the user. Also we can reuse existing events (e.g. standard JSF or Swing events), however this can be even more inconvenient for the end-user than specialized RichFaces API events.

                          I have already created 5 events for item moved, item resized, item selected, schedule load, view changed. Isn't this too much? I think not.

                          I agree with you - all these events are necessary and pass different data. What I can suggest is refactoring of org.richfaces.component.events.ScheduleListener interface into three listener interfaces: one for event modification/selection, other two for schedule load & view changed.

                          Which name do you prefer ScheduleLoadEvent or DateRangeChangedEvent?

                          I like DateRangeChangedEvent more, because this event is not called on initial rendering so ScheduleLoadEvent may be confusing. What do you think about DateRangeChangeEvent (changed -> change)?

                          How should parsing exceptions in decode method be handled? Packed into RuntimeException and rethrown, logged as warnings?

                          As far I understood, none of these values are typed by user directly, so there is no place for validation messages. Let's wrap and throw FacesException.

                          What's the difference between using scopeChain variables and object properties (i.e this.id) - check richfaces.fullcalendar.js

                          Looking into richfaces.fullcalendar.js, we can see that each new instance of RichFaces.FullCalendar object gets new brand set of functions, because they are created directly in constructor and are using closures for function arguments (i.e. "bind" to scoped variables). If you place these functions in RichFaces.FullCalendar.prototype, then these scoped variables won't be available and it will be possible to access them via object properties.

                          Last thing, I've run into frustrating problem in Webkit (safari,chrome) based browsers. If content type is set to application/xhtml+xml then some DOM modifications just won't work (i.e. div.innerHTML=" " will work from page, but not if it is located in external js file). This artilce http://j4fry.blogspot.com/2009/06/jsf-20-and-dojo-create.htmlsuggest to apply listener that would change the content type, but we cannot force people to do that to get our component working. Here is the link to issue in webkit bugtracker, it doesn't seem they are going to fix it. What shall we do? This is very, very old bug of webkit.

                          Ok, I'll think what we can do. Facelets use xHTML by default, so it should be somehow handled. BTW, you can use:

                           

                          <f:view contentType="text/html">
                          

                           

                          to switch to HTML mode.

                          • 25. Re: Schedule
                            nbelaevski

                            Update: I've checked Webkit bug. As a workaround, we can use numerical entities like &#160; instead of &amp;nbsp; and inform author(s) of fullcalendar.js about the problem.

                            • 26. Re: Schedule
                              blabno

                              Hi Nick,

                              Thanks for thorough answer. I've fixed fullcalendar.js as you suggested and the widget rocks under Chrome. I've also posted an issue at fullcalendar bugtracker. I've added listener tags for each event and split ScheduleListener into 6 different listeners (also added new event).

                               

                              Widget has an option to revert item moving or resizing. I've implemented it in such a way that listener bound via EL can return boolean which is used to decide if revert is required (in other words if modification is allowed by server side code). As for now, listeners attached via tags or UISchedule.addXXXListener cannot veto the operation. Do you think, they should? If so then how? I think that we cannot use returned value because it would be eaten by xxxEvent.processListener. We could allow throwing java.beans.PropertyVetoException, but then I guess we cannot pass such event to super.broadcast which I've put now at the end of broadcast() method. I guess it should be done like this:

                               

                              if (event instanceof ScheduleDateRangeChangedEvent) {

                                ...

                                super.broadcast(event);

                              } else if (event instanceof ScheduleItemMoveEvent) {

                                FacesContext facesContext = getFacesContext();

                                AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext);
                                MethodBinding expression = getItemMoveListener();
                                boolean allow = true;
                                if (expression != null) {
                                  Object result = expression.invoke(facesContext, new Object[]{event});
                                  allow = ((Boolean) result);
                                }

                                try {

                                  super.broadcast(event);

                                } catch(PropertyVetoException e) {

                                   allow=false;

                                }

                                ajaxContext.setResponseData(allow);

                              } else if (event instanceof ScheduleItemResizeEvent) {

                                ...

                                super.broadcast(event);

                              } ... else {

                                   super.broadcast(event);

                              }

                              Yet there is a question: should all listeners be notified even if event was vetoed by anyone? Also what should be fired first, EL bound listener or the ones attached by API or tag?

                               

                              Shall we enumerate firstDayOfWeek as in Calendar (sunday=1,monday=2,etc.) or like in widget(sunday=0,monday=1,etc.)?

                               

                              As to naming, I've made a distinction: events that can be vetoed are named in present form and ones that cannot be undone use past form of verb, i.e.: DateRangeChangedEvent (range was changed and nothing can revert it), ScheduleItemMoveEvent (there is an attempt to move item, but listeners may veto it). What do you think about this convention? If you don't like it we can change all names to use present form of verb.

                               

                              Widget caches initialEvents. Perhaps it should not because state on server side may change. Note that in ajax mode when you navigate one month back, the request is made, but when you navigate back to initial month, then no request is made and widget uses old values. Well, actually it is our facade that does that:).

                               

                              Shouldn't we check if there is at most one renderable UIScheduleItem child?

                               

                              How about reRender,ajaxSingle and others? How to put such info into generated js function?

                               

                              What about Text/Time Customization ? I think, we should provide appropriate entries in messages.properties, but who to pass it to widget? There are two options:

                              1. put everything in options (bad because request size grows)
                              2. generate script resource (I don't know how, please point me to some example) and attach it with <script src="..."/>; such script would have to contain something like this : jQuery.extend(RichFaces.Schedule.messages,{'pl':{monthNames:...}} if locale is set to polish

                              As to option 2, i'm trying to extend InternetResourceBase and override getResourceAsStream, but I can't figure out how to access appropriate resource bundle.

                               

                              edited later:

                              As to text/time customization point 2:

                              Ok, so I've found out that overriding needFacesRequest() method to return true turns FacesContext on. But next question arises. In JSF 1.1 there can be only one message bundle (which is easy to access via FacesContext.getCurrentInstance().getApplication().getMessageBundle()). If user uses only one file with messages that's fine, but since JSF 1.2 users can use multiple resource bundles. Should our component be aware of this? If so then I do not know how to get names of all defined resource bundles. Also Seam based apps use their custom mechanism for multiple messages files. Users used to such facility will have hard times figuring out how to configure their app so that schedule uses their custom messages. What is your proposition?

                              • 27. Re: Schedule
                                ilya_shaikovsky
                                Widget has an option to revert item moving or resizing. I've implemented it in such a way that listener bound via EL can return boolean which is used to decide if revert is required (in other words if modification is allowed by server side code). As for now, listeners attached via tags or UISchedule.addXXXListener cannot veto the operation. Do you think, they should? If so then how?

                                About rejecting drop.

                                 

                                From the first look making return from listener - isn't looks good from JSF Event-Listeners paradigm.. My general thoughts about that:

                                • some kind of validator normally do the job on checking new objects before any model updates. But in your case model updated before the rejection logic. (Although validators not looks convenient for this concrete case.)
                                • Listeners for components in general called at Invoke Application phase  and normally called to process action event or some model update event which already occured and so can not cancel it.

                                 

                                So how about next way:

                                 

                                • you just rise event to listener which contains information about item which were dropped and item to which drop occured.
                                • Listener logic(implemented by end developer) should be fully responsible for checking requirements and performs model change itself. If no changes performed by the listener - changes not occurs. If need listener could rise messages.

                                 

                                Examples:

                                 

                                • tree drag and drop - the developer fully responsible for actions to be performed with the model if one node was dropped to another.
                                • FileUpload - file uploaded by the component but the developer fully responsible to choose storage and place the file there when event came to listener. In the same time he could reject them for any reason and add some message to context.

                                 

                                And for resize - i think it could be just some client side solution.. Because I do not see at first look how this could be related to some server side logic.

                                • 28. Re: Schedule
                                  blabno

                                  Problem with component is that items are not rendered as standalone html, but are created by main component via JavaScript, so we cannot use it as standard UIData component that only renders children. (well, we could, but we would have to reRender entire widget on every request - item resize, move, etc. and that would decrease performance and make widget blink).

                                  Probably we could force widget to refetch items without rendering after each event, but that would cause 2 ajax requests per event (one to raise event and one to refetch items) and drastically increase traffic.


                                  edited later:

                                  I've implemented full internationalization support via standard JSF mechanism.

                                  I've also adopted new version of fullcalendar with option to quickly create items via click-drag.

                                  Check out demo.

                                  Source code is available at svn://bernard.labno.pl/richfaces

                                  • 29. Re: Schedule
                                    quinindiola

                                    Hi,

                                     

                                    I am trying to test your Scheduler component but I am unable to download the source code from your SVN server. Can you check the server is online?

                                    You have done a great job !!

                                     

                                    Thanks

                                    1 2 3 4 Previous Next