Changes between Version 40 and Version 41 of S3XRC/ResourceReport


Ignore:
Timestamp:
11/26/11 15:34:38 (10 years ago)
Author:
graeme
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • S3XRC/ResourceReport

    v40 v41  
    394394
    395395...and that's it.
     396
     397== A View of Sahana-Eden ==
     398Their are a number of bits and pieces that make up the view and understanding what they are and how to interact with them is essential when developing Sahana-Eden. So taking the screenshot below of a standard screen, listing all of the instances of a particular resource.
     399[[Image("Resource details.png")]]
     400The various pieces that make up the screen are:
     401* Main menu
     402* Sub menu or the menu specific to the model
     403* Title
     404* Action Buttons
     405* Sub title
     406* dataTable
     407The menus (the first two bits) are common for all screens with the model specific menu being defined in the models/01_menu.py file. The rest of the view lies within the content div.
     408=== The screen title and subtitle ===
     409The first element in the content is the Title, this is a simple H2 tag but it has been nicely formatted by the style sheet to stand out. The title can set up with a simple assignment as follows:
     410
     411{{{output["title"] = "List of Assessment Series"}}}
     412Within the controller logic the output variable is returned by the call to the s3_rest_controller() and it is also available in the post processor function, so this line of code can be included in either the preprocessor or after the call to {{{s3_rest_controller()}}}.
     413
     414The output variable is a simple dictionary and so setting up a key in this dictionary with the value of “title” is sufficient. But this piece of code is not at all friendly for people who work in another language. The string needs to be translatable which is done by passing it to the T() function.
     415
     416{{{output["title"] = T("List of Assessment Series")}}}
     417The same string may be used in a number of different screens and so to help with consistency the string can be defined in one place and then reused. This is done in the model
     418
     419{{{s3.crud_strings[tablename] = Storage(
     420            title_list = T("List of Assessment Series"),
     421            )}}}
     422
     423The {{{tablename}}} variable has been set up to the name of the table. Other strings can be added here, so it becomes a convenient holder for all the string to be used by the model. Finally, because the title is such a common requirement in a form if a title_list value is set up for a list view then that string will be automatically used. That means that the {{{output["title"]}}} assignment is not necessary unless you want to use a different string.
     424
     425That's quite a bit of background to only produce a title, but what you have learnt for the title is the same for the subtitle. The special crud name for a subtitle belonging to a list view is {{{subtitle_list}}}, so all you need to do is define that in the {{{s3.crud_strings}}} variable, and should you want to override the default value then assign the new value to {{{output["subtitle"]}}}.
     426
     427=== Crud generated buttons ===
     428Their are a number of buttons that are automatically added to the screen depending upon the context. For a list the add resource button will be displayed. If you want this button then you don't need to do anything. However, if you wish to suppress the button from being displayed then the following will help:
     429{{{
     430    s3mgr.configure(tablename,
     431                    listadd=False,
     432                   )
     433}}}
     434This code will go in the controller before the call to {{{s3_rest_controller()}}}.
     435
     436=== dataTable ===
     437This displays all of the resources and adds buttons to open (or edit) and delete the selected resource. Again all of this comes as part of the framework and can whilst the default settings are often sufficient it is possible to adjust the the way the dataTable looks by changing various settings.
     438== Resource Details ==
     439Opening a resource on the dataTable will then display details about this resource. From the workflow perspective a resource consists of a number of actions that can be performed on the resource. These actions might, for example display the resource data, generate more data or trigger off more action. The screenshot below of a standard screen, showing the details of a particular resource.
     440[[Image("List of Resources.png")]]
     441The various pieces that make up the screen are remarkably similar to the first screen. The main additions are:
     442* rHeader
     443* tabs (within the rHeader)
     444This particular screen also has some extra details after the subtitle. This was added by creating a new view based on the standard list view but adding an extra slot to hold the help information about the list.
     445=== rHeader ===
     446The rHeader is an area on the screen to display summary details about the resource. The details of the rHeader will be set up in a function and the function can then be passed as a parameter to {{{s3_rest_controller()}}}. The rHeader callback function receives an {{{S3Request}}} object and should return the HTML which will be displayed on the screen. Typically the HTML returned would be a DIV object, with one HTML element within this being the tabs.
     447=== tabs ===
     448These are a convenient mechanism for displaying the options (links) available, and where appropriate they can follow the workflow of the resource. The tabs are set up by building a list of tuples, each tuple consists of the label followed by the action. This list is then passed to {{{rheader_tabs()}}}, which renders it into HTML ready to be added to the rHeader DIV.
     449
     450So the key to the tabs is the list of tuples, an example of one looks like this:
     451{{{
     452if auth.s3_has_permission("create", "survey_series"):
     453    tabs = [(T("Series Details"), None),
     454            (T("New Assessment"), "newAssessment/"),
     455            (T("Completed Assessments"), "complete"),
     456            (T("Series Summary"),"summary"),
     457            (T("Series Graph"),"graph"),
     458            (T("Series Map"),"map"),
     459           ]
     460}}}
     461The labels that appear on the screen are wrapped in a T() so that they can be translated. The action is either a string that relates to the type of action that will be performed, or None which means that the default action will be performed.
     462The actions though are the real power of the tabs. They can be any from:
     463* A default value
     464* A component of the resource,
     465* Another controller or
     466* A method.
     467=== default tab action ===
     468The default action will be an edit of the full resource details if the user has sufficient permissions otherwise it will be a read of the resource details.
     469=== component tab action ===
     470In the example given the database has a table called survey_complete and so complete is a component of the series resource. This will then display, in a list (dataTable), all the complete records that belong to the resource that had been selected. The component records can then be edited or deleted and this is all managed with the main resource UI, providing a consistent interface for the user.
     471=== another controller tab action ===
     472Not all parts of the workflow are coupled as tightly as a resource component relationship. For such cases it might be easier to switch to a completely different controller. To ensure that the consistency of the interface is retained the same rHeader should be used, but as already explained setting that up is a cinch. In the example above newAssessment is an example of an external controller. Note that in the tab it is followed by a slash.
     473=== method tab action ===
     474The method will be called by the same controller so it will inherit the pre and post processing. It is typically a function that will work with the same table but needs to perform something beyond the basic CRUD actions. In the example above summary, graph and map are all method actions. Because they are not controller functions they need to be set up a little differently. The method will be set up with the models (not the controllers) and the outline of the method is:
     475{{{
     476def seriesMap(r, **attr):
     477
     478    # retain the rheader
     479    rheader = attr.get("rheader", None)
     480    if rheader:
     481        rheader = rheader(r)
     482        output = dict(title=T("Do Something with the Template"), rheader=rheader)
     483    else:
     484        output = dict()
     485    crud_strings = response.s3.crud_strings["survey_series"]
     486
     487    # code specific to this method - creates the map
     488
     489    output["title"] = crud_strings.title_map
     490    output["subtitle"] = crud_strings.subtitle_map
     491    output["form"] = form
     492    output["map"] = map
     493
     494    response.view = "survey/series_map.html"
     495    return output
     496}}}
     497This method now needs to be linked to the controller, again this code should be in the model.
     498{{{
     499s3mgr.model.set_method("survey", "series", method="map", action=seriesMap)
     500}}}
     501Because the method gets and then stores the rHeader it is possible for the call to originate from different controllers but the UI will remain consistent.