|
YOUR FEEDBACK
Did you read today's front page stories & breaking news?
SYS-CON.TV |
TOP THREE LINKS YOU MUST CLICK ON General Java Prototyping an Advanced Calendar Class
Prototyping an Advanced Calendar Class
Oct. 1, 1997 12:00 AM
It is possible to create a very attractive look-and-feel prototype of a Calendar-based browser application in JavaScript, but to compete with tough-minded mainframe legacy systems such as MEMO requires a highly functional and scalable working prototype to justify the continued investment and potential encapsulation of a large mainframe system. In Part 1, I discussed the Calendar functionality, prototyping success factors and the design constraints imposed by the corporate platform and JavaScript itself. I introduced an event-action model that supported asynchronous event handling between dependent objects and also the disposable requirement for an elementary client-based datastore. In this article, I continue with the technical detail of cookies, Calendar classes and the generation of the user interface using JavaScript. Essentially, we are coding the overriding of class methods manually in order to maintain a very simple interface to reasonably sophisticated objects based on how the data is used. this allows the dynamic rendering of an object's data based on simple object dependencies.
Elementary Datasets Using Cookies The section Calendar Data' in Part One (JDJ, Vol. 2, Iss. 9) introduced the concept of cookies. The following sections describe in detail how cookies are used by the Calendar. Cookie data has been treated as the most disposable part of the prototype, but the interface to the data has not. In the absence of a CGI/DBMS treatment, formatted data (cookies on the PC or text files on a server) will be required for some time. Formatted strings represent the datasets used Calendar data is stored in cookies. Some are used as control flags, as in Table 1. Each month had a separate cookie denoted by Mmmyyyy. This contained the complete, unordered set of meetings for that month, representing a heap structure. The record format of each meeting is described in Table 2. The field delimiter is the tilde (~) character. Participants are chosen by name from the Select Participants popup, but only the e-mail address is stored. The participants sub-string was a list of e-mail addresses delimited by newline (\r\n), as in the following code sample: pmanager@itlan.office.co.uk\r\nbill@itlan.office.co.uk\r\n. Using the escape() and unescape() functions of JavaScript, the \r\n' characters are converted to %0D%0A' when cookie data is written and back to \r\n' when cookie data is read for both the participants list and the supplementary text field. An example meeting string is shown in the following sample:
20~Team Meeting~13~20~25~pmanager@it.office.co.uk\r\ Some functions can be implemented on the server as database procedures in order to reduce the client/server dialogue and the associated, long code path; in particular, the sequence value function, which in a DBMS treatment could have the surrogate key generated on the server in the same transaction as the insert of the data, thus removing the processing from the client. However, on a distributed client/server platform with many users and high concurrency, with many potential sequence value calls to lock the same table row and incur wait, a client-based surrogate key is the best option, but needs careful management. Sequencing Meetings using the sequence_value class A meeting number is generated using the get_next_meeting_number() method from the sequence_value object to obtain the next meeting number. All meeting numbers generated on the client are unique. The last used meeting number is stored in a cookie, sequenceValue , which is incremented and updated on demand, as shown in Listing 1. The sequence value class is defined as follows:
function sequence_value() An object is created when the HTML page loads, using the JavaScript onLoad() event handler sv = new sequence_value() and the methods invoked when a meeting object (this) is created: this.meeting_number=sv.get_next_meeting_number();
Parsing Formatted Data Because only Meeting level data is stored, a method was implemented in the Meeting class to parse the single meeting extracted from the cookie. Another method was implemented in the Meeting class to format a cookie string in order to write data to the cookies file. The Day object controls the extraction of all meetings in the day by filtering out those meetings with that day number.
Parse Data - Meeting Class
Parse Meeting - Day Class Before: m1f1~m1f2~m1f3~m1f4~..~m1f9~m2f1~m2f2~ etc. After: m1f1~m1f2~m1f3~m1f4~..~m1f9~|m2f1~m2f2~ etc. Note the ~| character pair: the | denotes end of meeting, so the String.split() statement would operate as shown in Listing 3. In Listing 4, the keyword this' refers to the Day object.
Format Meeting Data Note: We can't use the expression for (i in this)' to yield each member of the Meeting class because the expression is not guaranteed to return members in the same order between JavaScript versions.
Cookie Constraints A more important constraint is the implicit HEAP nature of the stored data. In a relational database (e.g., Ingres), a HEAP table is a table which has no order. Records are appended to the table in arrival sequence. The same goes for the meeting data, which is appended to the cookie string. Each inserted meeting is appended to the last regardless of day or time. When meetings are rendered, the meetings are listed in arrival sequence. This means that to update and delete data the string has to be scanned from the start until the meeting has been identified using the meeting number. An update is a deletion followed by an insert. Deleted space is reclaimed in the cookie by the code that implements the delete. Although JavaScript is interpreted, there is no real visible performance degradation using these heap-based scanning methods, but there is more code to maintain. Again, priority is given to delivering the critical functionality.
Calendar Object Model
Figure 1 shows a simple object model for the Calendar.
For simplicity, we can pretend that there are two dependencies in this very simple object model. Because the objects are used in two different ways, we can have two dependencies; reading and formatting data (B) and object construction (A)
What seems like over-engineering a very simple set of objects actually assists in allowing us to do three things: By attempting to maintain some form of abstract inheritance hierarchy for the objects, we hopefully can rely on the specialization to request the construction of its super' object (A). So, when we create a meeting object, we want the Meeting object to be initialized within a Day and the Day within the Calendar month. Conversely, when we want to display summary meeting details within the context of a day, we want the rendering to be controlled by the Day, which will generate the HTML around the meetings, which are then called upon to render their information in HTML.
Remember that when viewing meetings in a day, they can be viewed: Essentially, we are coding the overriding of class methods manually in order to maintain a very simple interface to reasonably sophisticated objects based on how the data is used. Using this reversible approach to dependencies, we can work with the loose typing of JavaScript to take handles at both ends of the object model. We can create a meeting object which will invoke methods in the containing class to position it. We can also display a meeting by invoking the appropriate higher level context. For example: To create a new meeting object which will invoke a method in a containing object: new meeting() The meeting constructor will store the position it occupies in the array of meeting objects (day): this.position_in_day_list = Day.new_meeting( this ); The Day.new_meeting() method assigns the meeting object to the next free slot (see Listing 6)
Generating Screens Using JavaScript When the user clicks <SELECT>, the select_calendar() method is called and the form is passed to the method (see Listing 7). The calendar object retrieves the selected values from the pull down lists (Month View). The calendar object creates a Date object, which is used to render the calendar by selecting values from the pull down lists, as shown in Listing 8. The calendar object loads the data and writes to the calendar window (Month View) (Listing 9). Create the HTML text in JavaScript for the Month View In JavaScript (1.0), you have to be careful when concatenating strings because each +' operator creates a result that isn't garbage-collected until the page is unloaded. For example, to create a HTML table, see Listing 10.
The Day cell has summary meeting info written to it The same method will be called regardless of the target window. In Java, a display method would be overloaded for each specific target window. In JavaScript, we encapsulate the window format in one method instead of defining many function references in the Day or Meeting class. Meetings are rendered differently in each window, but by keeping the interface the same we let the objects render themselves depending on the target window. So we have encapsulated the way data is formatted for display. In this way, the Calendar (either the whole Calendar, a Day or a Meeting) is passed to different windows and the data displayed as appropriate. In the following, the calendar has created a meeting object for every meeting in the month and allocated each meeting to the Day object for the day in which the meeting resides. The Calendar object contains a Day object for each day that contains a Meeting. Remember the need to manage JavaScript resources discussed in Part One? Note the use of var' inside the for' parentheses. Before the for', the variable does not exist. Outside the for', the variable will be discarded. You can use this optimization to control how much local storage you require at a given moment. This technique shouldn't be used in a loop where the allocation/deallocation of the local variable will take place repeatedly. The user may express a preference for how the Month View is displayed. Summary meeting details are displayed as text, as a scrollable list or as a pulldown list. The user's display preferences are stored in cookies called userPreference1/2, and the <HELP> button on the month view allows the user to customize the preference. The code in Listing 11 renders the calendar grid. The this' operator refers to the calendar object that contains the render_calendar() method. The Day object requests all Meetings to render the Subject A JavaScript string is used to store the HTML text for the Day cell that will contain the HTML which renders the summary meeting data. The user preference is used to select the different HTML tags. Two cookies are used, userPreference1 and userPreference2. The values of the user preferences are shown in Table 3.
These values are set from the User Preference screen (Figure 3), which is selected using the
Each Meeting object that has a slot in the Day object has the render_subject method invoked.
Figure 4 shows the typical rendering of calendar events. Figure 5 is a snippet from the same screen, but the user preference is a pulldown list of Calendar events. Figure 6 is another snippet from the same screen as Figure 4, but the user preference is a scrollable list of Calendar events.
If embedded text is displayed, we can't scroll or pull down, so we have to display a continuation message.
If we view Day as a specialization of Meeting because of the variable rendering requirements controlled by the Day class, then we are effectively calling the super()' method of Day.
Using this reversal, we can code an artificial overriding which is kept in line by the requirement that each class implements its own display methods; the rule being that all pseudo overriding of methods have identical names.
Remember that this HTML is generated for the main calendar window (or frame), which only contains embedded calls to methods in the controlling window (or frame), cal_control. This controlling window also contains the data objects. Because both frames share the same parent, there is no risk that closing a window will destroy the embedded references, which would be the case if they were separate window instances. JavaScript 1.0 does not give the user control over the dependencies between windows that may share window references.
Note how the Day object is used in Listing 12. For each meeting in the array of Meeting objects (Day), we invoke the render_subject() method of the meeting. In Listing 12, the this' operator refers to the Day object, which is the dense array of meeting objects.
The render_subject() method of the meeting object (see Listing 13) generates either a simple text string or an element of a HTML <SELECT> tag, the <OPTION> tag. For the <OPTION> tag, the value is the position which that particular Meeting object has in the Day object. When that option list element is clicked, the value is used by the calendar to display the meeting details in the right frame of the Browse Meetings window.
Conclusion
The main technical focus has been on using JavaScript in a variety of ways: to generate HTML, parse formatted data streams and handle events asynchronously. Although JavaScript is a moderately simple scripting language, an object model was implemented which allowed the manual overriding of class methods to be demonstrated in a language that does not support inheritance.
There are lots of practical tips and example screens to show how JavaScript interacts with HTML and browser objects to give vitality to the look and feel of the application. The article has also demonstrated how windows-like' a JavaScript application can be. The Select Participants' pop-up screen looks familiar to windows users, but is generated by JavaScript from the browser and is a browser window. Builders can employ the method described here of using cookies in their own JavaScript applications.
From the project lifecycle perspective, the article has addressed functional prototyping, design and build, within the context of managing (corporate) user expectation against competing legacy applications.
Those employed in making decisions on which technology to use to migrate a legacy application to a GUI interface will find a practical case for using the browser and JavaScript, with the added incentive of an application delivery vehicle that is platform independent.
Designers and builders who may simply wish to know more about the advanced uses of JavaScript can use the implementation details covered. Those involved with making decisions on what and how to prototype should be able to use the criteria in this article to clarify and enhance their own decisions. LATEST JAVA STORIES & POSTS
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK SPONSORED BY INFRAGISTICS
BREAKING JAVA NEWS |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||