The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

Introduction

This document describes the Controller object used in GBrowse. There is a section describing the controllers methods and a section describing how events drive the Controller object.

Controller

The controller object is used in GBrowse to handle the asynchronous events such as scrolling and track loading. In the controller.js script, the "Controller" variable is initialized.

  var Controller = new GBrowseController; // singleton

This object can then be used through out GBrowse.

Class Utility Methods

initialize

Simply sets up the instance variables that will be used.

reset_after_track_load

This method is called after any track load. It adds the drag and drop feature to each group of tracks (overview, regionview, detailview) so that it doesn't break after loading a new track.

register_track

Takes a track name and type and creates a track object (track.js) from it. It then stores that object in the gbtracks hash by the track name for later use.

If the track is not a scale bar it will also set it's retrieve_tracks value to true (although this could be stored in the track object itself). This tells the Controller that it's okay to retrieve this track image from the server when it's time (in Controller.get_remaining_tracks()).

set_last_update_keys

Sets the time key for the supplied tracks so we know later if one is outdated.

set_last_update_key Sets the time key for a single track so we know later if one is outdated.

hide_detail_tracks

Hides the detail tracks in cases where they shouldn't be displayed for some reason such as the max segment being exceeded.

DOM Utility Methods

wipe_div

Takes the id of a div element and clears the innerHTML. It's handy.

update_scale_bar

This method updates a scale bar that is passed to it from update_coordinates.

append_child_from_html

Appends new html to the appropriate section. It does this by creating a temp element, reading the html into it and then moving the new html elements over the the parent.

When used to add a track, this keeps the other tracks intact.

Update Section Methods

update_sections

This method will update the sections whose ids are passed to it.

It calls the server with the update_sections flag set and the section ids as section_names parameters.

The server then creates the section html for each section and passes them back where the html is placed in it's respective section.

Signal Change to Server Methods

set_track_visibility

This method tells the server that a tracks visiblility has changed.

If the track is being displayed and the track is stale (based on its last_update_key), rerenders the track using Controller.rerender_track().

Kick-off Render Methods

first_render

first_render() contacts the server and tells it to start rendering the images. It gets back a list of the track keys that it uses to call Controller.get_multiple_tracks().

It sets the last update value for each track which is used to figure out if a hidden track is stale.

It also gets the segment_info object which is used for the rubber banding.

update_coordinates

This method is called when the user navigates on the reference map by "rubber banding" a section or zooming or recentering, etc.

First it determines if there is a view already being displayed (if not, it submits the search form).

Then, it greys out all the tracks so the user knows that the tracks are now outdated.

The server is called to tell it that segment has changed and it starts rendering the new images.

The server returns the new segment_info, the track_keys and the new scale bars.

The onSuccess method of the request then, updates the sections that are dependant on the segment for their output and kicks off Controller.get_multiple_tracks() to retrieve the track images.

add_track

This is wraps a track name in an array for add_tracks.

add_tracks

This method sends a message to the server requesting that new tracks neet to be added.

The server responds with by starting to render the tracks and returning a data structure with track keys and the div elements that will hold the track images.

The onSuccess method for the request loops through the tracks and registers the new tracks, append the new div elements to to the appropriate track group. It also keeps track of any tracks that need to be loaded and calls Controller.get_multiple_tracks() to retrieve them.

rerender_track

This method rerenders a single track. It is similar to update_coordinates but without changing the segment.

It greys the track image. Then, requests that the track be rendered from the server.

The onSuccess method sets up the track to be retrieved by Controller.get_remaining_tracks() and then Controller.get_remaining_tracks() is called.

Retrieve Rendered Track Methods

get_multiple_tracks

get_multiple_tracks() sets up for get_remaining_tracks() by creating the time_key for each track and setting each one's "retrieve_track" value to true.

Then calls Controller.get_remaining_tracks with the time key.

get_remaining_tracks

This method goes through all of the tracks and tries to retrieve the tracks that have a true value for "retrieve_track".

The method will stop requesting a track if another request for that same track has superseded it. The time_key is used to mark a specific instance of get_remaining_tracks() so that if a track has been requested again, the first instance will see that the track's time key no longer matches and ignore it. The time_key is checked in two places, before querying the server and before displaying the track.

Once the tracks have been retrieved, it checks to see if they are finished (aka AVAILABLE), broken (ERROR, EXPIRED...) or still pending. If any are still pending, it will call itself again after a brief wait (defined by the decay * the time_out) and try to get the remaining tracks.

Track Configure Methods

reconfigure_track

Called from within the track configuration balloon.

This method, will send the new configuration information to the server. If the track is still "show"n then it is rerendered, otherwise it is removed.

Controller.reconfigure_track() is called with the form elements serialized in a string. This is done because the balloon messes with the interaction of the controller with the form.

Plugin Methods

configure_plugin

All Controller.configure_plugin does is calls update_sections() to update the "plugin_configure_div" with the configuration form from the server.

reconfigure_plugin

This serializes the plugin configuration form and sends it to the server. When it hears back, it clears the div element holding the form.

If the plugin is an annotator, it reloads the affected track. If it is a filter, then it reloads

plugin_go

This method, takes the plugin type and figures out what to do with it.

An annotator will not have a "Go" button in its configuration form. So the Go button simply adds the plugin track and updates the track listing

A dumper will redirect to the dump page. If "Go" button was from the configuration form, then it will serialize and send the configuration info with it.

Note: As of this writing, Finder and Filter plugins don't do anything with the Go button.

Upload File Methods

edit_new_file

Updates the external_utility_div with the edit file form. This is the same form as when editing an existing file, it is just blank and it has a new file name attached.

edit_upload

Updates the external_utility_div with the edit file form. This is the same form as when editing a new file. It has the file name and the file contents populate the text area.

commit_file_edit

Submits the file edit form to the server. If a new file was created, it adds the track. Otherwise, it rerenders the track.

delete_upload_file

Tells the server to delete the file, removes the track from the panel and updates the track listing and external data table.

Remote Annotations Methods

new_remote_track

After a check to see if the url is not empty, it simply adds the track using Controller.add_track and updates the track listing and external data table.

Non-Class Methods

The following methods are not class methods and are therefor called directly.

initialize_page

This method gets the Controller ready and requests the first render of the images.

It creates a hash for the sections that update when the segment changes (segment_observers).

It then calls Controller.first_render().

It also initializes the objects that handle the rubber banding for the overview, region view and detail view.

create_time_key

This creates a time_key for identifying get_remaining_tracks() instances and for determining if a track is stale. It is simly a time integer.

actually_remove

Prototype's remove function doesn't actually remove the element from reachability. This function renames the "removed" element so it won't be accessible later.

Events

This section describes the GBrowse code's reaction to various events.

Standard Events

First Page View

- Client requests view of a page
- Server Creates Page

Server initializes the state and generates the page but does not begin rendering the images yet.

- Client Recieves Page
- Controller object created immediately

The Controller.initialize method is called which simply sets up the instance variables that will be used.

- Track Registration

Each track div has a call to Controller.register_track() which is run on load. Controller.register_track() creates a track object and stores it by track name.

- On Load, Controller.initialize_page() is called

Controller.initialize_page() creates a hash for the sections that update when the segment changes (segment_observers).

It then calls Controller.first_render().

It also initializes the objects that handle the rubber banding for the overview, region view and detail view.

- Controller.first_render()

first_render() contacts the server and tells it to start rendering the images.

It gets back a list of the track keys that it uses to call Controller.get_multiple_tracks().

It also calls Controller.set_last_update_keys() to set the last update value for each track which is useful later to determine if a track is stale.

- Calls Controller.get_multiple_tracks().

Controller.get_multiple_tracks() sets up for get_remaining_tracks() by creating the time_key for each track and setting each one's "retrieve_track" value to true.

Then calls Controller.get_remaining_tracks with the time key.

- If Not Displaying Details

If the details panel, usually because the max semgent has been exceeded, it calls Controller.hide_detail_tracks() to white out the tracks.

When the user navigates on the reference map by "rubber banding" a section or zooming or recentering, etc, that information is sent to the Controller.update_coordinates() method which begins the work of moving the view.

Controller.update_coordinates() controls the update process.

- Grey out old tracks
- Contact Server

Tell the server to that the segment has been updated. The server will then start rendering tracks and return segment info, track keys and scale bars

- Display returned scale bars

The Scale bars are generated immediately because they are quick. This provides the user with a visualization that the segment has changed. Updating is done with Controller.update_scale_bar().

- Updates sections

Calls Controller.update_sections() to update the sections whose content is based on the segment being viewed.

- New Segment Info Stored

The new segment_info object is stored so that rubber banding can still work.

- Sets last update keys for tracks

Controller.set_last_update_keys() sets the last update value for each track which is useful later to determine if a track is stale.

- Calls Controller.get_multiple_tracks().

Controller.get_multiple_tracks() sets up for get_remaining_tracks() by creating the time_key for each track and setting each one's "retrieve_track" value to true.

Then calls Controller.get_remaining_tracks with the time key.

- If Not Displaying Details

If the details panel, usually because the max semgent has been exceeded, it calls Controller.hide_detail_tracks() to white out the tracks.

Rubber Banding

- Start the rubber banding

In rubber.js, the SelectArea.prototype.startRubber is called. This calls "self.loadSegmentInfo()" which is defined in the subclasses overviewSelect.js, regionSelect.js and detailSelect.js.

- loadSegmentInfo()

This method which is defined in each of the subclasses, copies relevant segment information from the Controller.segment_info into the rubber object.

- Stretch the Rubber Band

As the rubber band moves, it makes the start < the stop and the search box updates.

- Finish

When the rubber band is finished, it passes the new segment information to Controller.update_corresponences() to do the navigation.

Selecting A Track's Checkbox

- Checkbox is selected

When a track Checkbox is selected, it calls the buttons.js method, gbCheck().

- buttons.js gbCheck()

This method finds the checkbox element which was checked and calls the buttons.js method gbToggleTrack();

- buttons.js gbToggleTrack()

Note: Here we just discuss what happens when a track is being selected for display. This method also handles deselection.

If the track has already been drawn it sets the div element to "block" (aka visible) and calls Controller.set_track_visibility() which tells the server that the track is now visible and if the track is stale, rerenders it. Then it is done.

Otherwise, it needs to add the track, so the method calls Controller.add_track().

- Controller.add_track()

Note: add_track() is a wrapper for add_tracks which can update several tracks at once.

add_track() sends a message to the server requesting that a new track be added.

The server responds with by starting to render the track and returning a div element that will hold the track image.

The onSuccess method for the request registers the new track, appends the new div element to to the appropriate track group and if needed, calls Controller.get_multiple_tracks() to retrieve the track.

Deselecting A Track's Checkbox

- Checkbox is deselected

When a track Checkbox is deselected, it calls the buttons.js method, gbCheck().

- buttons.js gbCheck()

This method finds the checkbox element which was unchecked and calls the buttons.js method gbToggleTrack();

- buttons.js gbToggleTrack()

Note: Here we just discuss what happens when a track is being deselected. This method also handles track selection.

If the track has already drawn it sets the div element to "none" (aka hidden) and calls Controller.set_track_visibility() which tells the server that the track is now hidden so that it won't be displayed if the page is reloaded.

Otherwise, it doesn't need to do anything.

Configure Track Submit

Configuring a track starts by hitting the question mark in the track title. A balloon pops up with the configure track form inside. If the "Change" button is hit, then interesting things happen.

- Call Controller.reconfigure_track()

Controller.reconfigure_track() is called with the form elements serialized in a string. This is done because the balloon messes with the interaction of the controller with the form.

- Report the new configuration to the server

The server stores the new configuration data in the state object.

- If track is still visible, rerender

If the "show" option was kept on, Controller.rerender_track() is called to rerender the track individually.

- If track is not visible, rerender

If the "show" option was turned off, remove the track from the being displayed (the server will already know about this). Reload the track listing to turn the check box off.

Plugin Events

"Configure..." Button Pressed

- Calls Controller.configure_plugin()

All Controller.configure_plugin does is calls update_sections() to update the "plugin_configure_div" with the configuration form from the server.

Configure Canceled

When the cancel button is pushed, all that needs to be done is call Controller.wipe_div() which will remove the html form from the page.

Plugin Configure

- Calls Controller.reconfigure_plugin()

This serializes the plugin configuration form and sends it to the server. When it hears back, it clears the div element holding the form.

If the plugin is an annotator, it reloads the affected track. If it is a filter, then it reloads all the tracks because there is no way to tell which track it works on.

"Go" Button Pressed

The "Go" button by the plugin selection box and the "Go" button in the configuration form both call Controller.plugin_go(). The only difference is for dumpers, where the form version will have the form elements serialized and sent to the server.

- If Annotator

An annotator will not have a "Go" button in its configuration form. So the Go button simply adds the plugin track and updates the track listing

- If Dumper

A dumper will redirect to the dump page. If "Go" button was from the configuration form, then it will serialize and send the configuration info with it.

- If Filter

Doesn't do anything

- If Finder

Not yet defined

Upload File Events

Upload File

This is not an asynchronous request. Due to security issues, AJAX does not allow asynchronous file uploads. There is a workaround that is not implemented. Google "AJAX file upload iframe" for more information.

"New..." Upload File

- Controller.edit_new_file()

Updates the external_utility_div with a new file form. Note that the file is named at this point but not created on the server until committed.

Edit Upload File

- Controller.edit_upload()

Updates the external_utility_div with a form to edit the selected file.

Commit File Edit

- Controller.commit_file_edit()

Submits the file edit form to the server. If a new file was created, it adds the track. Otherwise, it rerenders the track.

Delete Upload File

- Controller.delete_upload_file()

Tells the server to delete the file, removes the track from the panel and updates the track listing and external data table.

Remote Annotation Events

"Update URLs" Button

- Calls Controller.new_remote_track()

After a check to see if the url is not empty, it simply adds the track using Controller.add_track and updates the track listing and external data table.

Delete Remote Annotation

- Calls Controller.delete_upload_file()

The delete_uploads_file does everything needed to remove a remote annotation. On the server side it will try to remove the file but that's not much overhead for reusing this.