Index: openacs-4/packages/acs-core-docs/www/tutorial-pages.html =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/tutorial-pages.html,v diff -u -r1.12 -r1.13 --- openacs-4/packages/acs-core-docs/www/tutorial-pages.html 5 Nov 2003 14:46:52 -0000 1.12 +++ openacs-4/packages/acs-core-docs/www/tutorial-pages.html 11 Nov 2003 10:28:27 -0000 1.13 @@ -1,190 +1,133 @@ -
+
by Joel Aufrecht
OpenACS docs are written by the named authors, and may be edited
by OpenACS documentation staff.
-
Each user-visible page in your package has, typically, - three parts. The xql file contains any database queries, the - tcl file holds the procedural logic for the page and does things - like check permissions, invoke the database queries, and modify +
As a workaround for missing content-repository functionality, copy a provided file into the directory for tcl files:
+ cp /var/lib/aolserver/service1/packages/acs-core-docs/www/files/note-procs.tcl /var/lib/aolserver/service1/packages/myfirstpackage/tcl/
To make this file take effect, go to the APM and choose "Reload all files" for "MyFirstPackage".
Each user-visible page in your package has, typically, + three parts. The tcl file + holds the procedural logic for the page, including TCL and + database-independent SQL code, and does things like + check permissions, invoke the database queries, and modify variables, and the adp page - holds html. The default page in any directory is + holds html. The -postgres.xql + and -oracle.xql files contains + database-specific SQL. The default page in any directory is index, so we'll build that - first, starting with the tcl file: -
[service0@yourserver postgresql]$ cd /var/lib/aolserver/service0/myfirstpackages/www + first, starting with the tcl file:[service0@yourserver postgresql]$ cd /var/lib/aolserver/service0/myfirstpackages/www [service0@yourserver www emacs index.tclPaste this into the file.
ad_page_contract { This is the main page for the package. It displays all of the Notes and provides links to edit them and to create new Notes. - @author rhs@mit.edu - @creation-date 2000-10-23 + @author Your Name (you@yourserver.test) @cvs-id $Id$ - @param orderby indicates when the user clicks on a column to order by that \column - @return table_html preformatting html table constructed by querying the sam\plenotes table - -} { - {orderby:optional {title}} -} -properties { - table_html } -# define the columns in the table -set table_def { - {title "Note"} - {body "Contents"} - {edit "" {} {<td><a href="note-edit?note_id=$note_id">Edit</a></td>}} -} -# construct an html table from the samplenotes database table -set table_html [ad_table -Torderby $orderby notes_query { *SQL* } $table_def]There are several things to -note about the file:
The page begins with an - ad_page_contract function. - This is where we declare the input and output variables and - their types and restrictions. It's also where we document the - page, including descriptions of the parameters and return. - (More information about TCL - pages and page contracts)
We have one input variable, - orderby, which is optional - and defaults to title.
We have one output variable, table_html
We populate the table_html variable with a function call, ad_table, which does most of the work of generating an html table from a database recordset. We pass it several parameters:
- -Torderby $orderby
If the user has selected a column for sorting, this passes that information to the function.
- notes_query
This is the name of the SQL query that we'll put in the xql file.
- { *SQL* }
This is a dummy placeholder. It's possible to put sql directly in the tcl file, but this is deprecated because it's harder to make portable.
- $table_def
Here we pass in the variable we just constructed; it contains a list of column names and display titles.
Put the database query into a separate file. If the - database query is exactly the same for Oracle and PostgreSQL, it - can go into a file with the same name as the tcl file but an xql - extension, e.g., index.xql. If - it is database-specific, it goes in - index-oracle.xql or - index-postgresql.xql. The - format is the same in each case, an XML structure that contains - the SQL query. Create the file now.
[service0@yourserver www]$ emacs index.xqlNote that the - name parameter of the - fullquery tag exactly matches - the SQL query name specified in the - ad_table call. Also, the SQL query ends with a tcl function call that generates a SQL ORDER BY clause using several TCL variables.
<?xml version="1.0"?> -<queryset> - <fullquery name="notes_query"> - <querytext> - select note_id, - title, - body - from samplenote - [ad_order_by_from_sort_spec $orderby $table_def] - </querytext> - </fullquery> -</queryset>Create the user-visible page.
[service0@yourserver www]$ emacs index.adpThe first line indicates that this page should be rendered within the the master template, which defaults to /web/service0/www/default-master. The second line passes a title variable to the master template. The third line inserts the contents of the variable table_html. The last line is a link to a page we haven't created yet.
<master> -<property name="title">Sample Notes</property> -@table_html@ -<p><a href="note-edit">Add a note</a></p>
Before we can test these files, we have to notify the - package manager that they exist. (More precisely, the tcl and - adp will work fine as-is, but the xql file will not be - recognized until we tell the APM about it.).
Go to http://yourserver.test:8000/acs-admin/apm
Click on the samplenote link
Click Manage file information
- Check the values in the file type column for your files. A - question mark means the APM doesn't recognize the file - type and probably means you have mistyped a filename. -
- At the bottom of the file list page - click on the - watch all files link. - Unlike adp and tcl pages, xql pages get cached. (And new - xql files don't get loaded when they're watched or the - server is restarted.) Watching an xql file causes the APM - to load the contents of the XQL into memory so that it can - be used, and to reload it whenever the file is changed. - The watch will last until the server is restarted. -
Now that the APM is aware of your files, check to make sure that the self-documenting code is working.
Browse to http://yourserver.test:8000/api-doc/
Click Notes 0.1d
Click Content Pages
Click index.tcl and examine the results.
Go to http://yourserver.test:8000/note/. You should see this:
-Sample Notes -Your Workspace : Main Site : Sample Note +set page_title [ad_conn instance_name] +set context [list] -No data found. +template::list::create \ + -name notes \ + -multirow notes \ + -actions { "Add a Note" note-edit} \ + -elements { + edit { + link_url_col edit_url + display_template { + <img src="/resources/acs-subsite/Edit16.gif" width="16" height="16" border="0"> + } + sub_class narrow + } + title { + label "Title" + } + delete { + link_url_col delete_url + display_template { + <img src="/resources/acs-subsite/Delete16.gif" width="16" height="16" border="0"> + } + sub_class narrow + } + } -Add a note. +db_multirow \ + -extend { + edit_url + delete_url + } notes notes_select { + select ci.item_id, + n.title + from cr_items ci, + mfp_notesx n + where n.revision_id = ci.live_revision + } { + set edit_url [export_vars -base "note-edit" {item_id}] + set delete_url [export_vars -base "note-delete" {item_id}] + } +
Now index.adp:
+<master> + <property name="title">@page_title;noquote@</property> + <property name="context">@context;noquote@</property> +<listtemplate name="notes"></listtemplate> +
Now we create the add/edit page. If note_id is passed in, + it edits that note. Otherwise, it presents a form for adding + notes. Edit + note-edit.tcl:
ad_page_contract { + This is the main page for the package. It displays all of the Notes and provides links to edit them and to create new Notes. -foo@yourserver.test -
Since our table is empty, it's a pretty boring page. So next we'll make it possible to add records.
If you get any other output, such as an error message, skip to Section�, “Debugging and Automated Testing”.
We'll create a single page to handle both adding and - editing records. In this recursive approach, the same tcl - function can present a blank HTML form, present the same form - pre-loaded with an existing record, and handle the resulting - submission of either updated or new records. This recursive - approach reduces the total amount of code and files. First, - create the tcl:
[service0@yourserver www]$ emacs note-edit.tcl
Paste and save and edit:
ad_page_contract { - Simple add/edit form for samplenote. + @author Your Name (you@yourserver.test) + @cvs-id $Id$ + + @param item_id If present, assume we are editing that note. Otherwise, we are creating a new note. } { - note_id:integer,optional + item_id:integer,optional } -set user_id [ad_maybe_redirect_for_registration] -set title "Add a note" -if {[exists_and_not_null note_id]} { - set title "Edit a note" -} - ad_form -name note -form { - note_id:key - {title:text - {label "Title"} - } - {body:text(textarea) - {label "Body"} - } -} -select_query_name note_query -new_data { -db_1row do_insert { *SQL* } + {item_id:key} + {title:text {label Title}} +} -new_request { + permission::require_permission -object_id [ad_conn package_id] -privilege create + set page_title "Add a Note" + set context [list $page_title] +} -edit_request { + permission::require_write_permission -object_id $item_id + mfp::note::get \ + -item_id $item_id \ + -array note_array + + set title $note_array(title) + + set page_title "Edit a Note" + set context [list $page_title] +} -new_data { + mfp::note::add \ + -title $title } -edit_data { -db_dml do_update { *SQL* } + mfp::note::edit \ + -item_id $item_id \ + -title $title } -after_submit { -ad_returnredirect "index" -}
We use ad_form - to automate most of the work here. Ad_form is a wrapper for the - template - functions for creating HTML forms. These functions should - always be used for HTML forms; this promotes consistency and, - since all template functions use the same stylesheet system, makes it easy to change - the appearance of forms.
The page takes a single, optional input parameter, - note_id. If it's present, ad_form will assume that we're editing - an existing record, look up that record, and pre-populate the - form. We'll also check and change the page title if necessary. We check user_id with ad_maybe_redirect_for_registration, - which will redirect to the login page (with an automatic return - path to bring them back after login or registration) if the - visitor isn't logged in. Then we call ad_form, specifying the - primary key of the table, the fields we want to edit, and - functions for insert and update.
Next, we create the database functions.
[service0@yourserver www]$ emacs note-edit.xql
<?xml version="1.0"?> -<queryset> - <fullquery name="do_insert"> - <querytext> - select samplenote__new(null,:title, :body,null,:user_id,null,null) - </querytext> - </fullquery> - <fullquery name="do_update"> - <querytext> - update samplenote - set title = :title, - body = :body - where note_id = :note_id - </querytext> - </fullquery> - <fullquery name="note_query"> - <querytext> - select title, - body - from samplenote - where note_id = :note_id - </querytext> - </fullquery> -</queryset>
Create the user-visible page:
[service0@yourserver www]$ emacs note-edit.adp
<master> -<property name="title">@title@</property> -<property name="context">{@title@}</property> -<formtemplate id="note"></formtemplate> -
The property tags are passed to the master template, which - uses their values to set the page title and context bar - (breadcrumb trail). We use the same variable, - title, for both variables but - wrap it in curly brackets for context so that the spaces aren't - interpreted separators. The formtemplate tag outputs the form - html with the matching name.
Go to the APM as before and reload. Then test all this by going to the package home page and adding and editing a few records.
Put your new work into source control.
[service0@yourserver www]$ cvs add *.adp *.tcl *.xql
-cvs add: cannot add special file `CVS'; skipping
-cvs add: doc/CVS already exists
-cvs add: scheduling file `index.adp' for addition
-cvs add: scheduling file `index.tcl' for addition
-cvs add: scheduling file `index.xql' for addition
-cvs add: scheduling file `note-edit.adp' for addition
-cvs add: scheduling file `note-edit.tcl' for addition
-cvs add: scheduling file `note-edit.xql' for addition
-cvs add: use 'cvs commit' to add these files permanently
-[service0@yourserver www]$ cvs commit -m "new work"
-/cvsroot/service0/packages/samplenote/www/note-edit.xql~,v <-- note-edit.xql
-(many lines omitted)
-initial revision: 1.1
-done
-[service0@yourserver www]$
And note-edit.adp:
<master> + <property name="title">@page_title;noquote@</property> + <property name="context">@context;noquote@</property> + <property name="focus">note.title</property> + +<formtemplate id="note"></formtemplate>
And the delete page. Since it has no UI, there is only a + tcl page, and no adp page. Edit +note-delete.tcl:
ad_page_contract { + This deletes a note + + @author Your Name (you@yourserver.test) + @cvs-id $Id$ + + @param item_id The item_id of the note to delete +} { + item_id:integer +} + +permission::require_write_permission -object_id $item_id + +mfp::note::delete -item_id $item_id + +ad_returnredirect "."