Forum OpenACS Development: Help with xowiki

Collapse
Posted by Antonio Pisano on
Hello there,

I am building an application on top of xowiki. The package itself covers nearly 100% of the features I need to implement, but I am having some head scratching with the remaining ones.

The requirements for my application is to assign a date the page is referring to. For example, let's say this pages will talk about historical events, I need to say that page "Columbus discovers America" refers to date 1492-10-12.

I guess I could obtain this by subclassing ::xowiki::Page and add a new slot, but as I am trying to exploit the most of xowiki, I wonder if there is another way to add a property like this to a page that would require no coding at all, just some fiddling with the UI.

Any hint on this?

Collapse
2: Re: Help with xowiki (response to 1)
Posted by Gustaf Neumann on
Don't subclass ::xowiki::Page, but use xowiki::Forms. Test easiest solution is to create an xowiki::Form with the field(s) you need. Then activated the MenuBar and define there a "New" operation to use this form.

If you need the field for quick indexing, enable hstore.
-g

Collapse
3: Re: Help with xowiki (response to 2)
Posted by Antonio Pisano on
Thanks Gustaf, I remembered something like that, but this time I am resolute in figuring it out!

...I think I have stumbled in a leftover tree_sortkey. Here is what happens:
- create a Form
- try to fill it out, creating a FormPage instance
- delete created instance

Problem comes from acs_object::get proc. In xql file
packages/acs-tcl/tcl/object-procs-postgresql.xql
there is still tree_sortkey in the query.

I will go that direction and maybe poke you some more later 😊

Collapse
4: Re: Help with xowiki (response to 3)
Posted by Antonio Pisano on
actually, tree_sortkey was fixed in 5-9, but not in main, as stated in cvs browser
Collapse
5: Re: Help with xowiki (response to 4)
Posted by Gustaf Neumann on
Dear Antonio,

i am not sure, what you are referring to. Do you mean the tree_sortkey from acs_objects, which was removed by part 4 of the OpenACS 5.9 agenda [1]? Maybe some confusion happens due to fishey, which makes an entry to the HEAD branch for every file added to in a non-HEAD branch (e.g. upgrade scripts).

Currently, all new development is happening in the oacs-5-9 branch (see as well agenda). Once, development in oacs-5-9 is finished, development will continue in the HEAD branch.

-g

[1] https://openacs.org/xowiki/openacs-todo

Collapse
6: Re: Help with xowiki (response to 5)
Posted by Antonio Pisano on
Yes, I run on a fresh OpenACS and probably I took code from HEAD. In 5-9 I saw it was fixed, sorry.

I was capable of adding my date attribute to the form, great! Now I would need to build some UI for my FormPage instances. For now I could stick with typical operations like list of objects, searchable by their attribute and CRUD operations.

CRUD is not a problem, but for listing I could use some advice. What is the recommended way to search a xowiki object by some user-defined attribute? I am trying to obtain the typical list with a form of filters aside (for now).

Collapse
7: Re: Help with xowiki (response to 1)
Posted by Gustaf Neumann on
Hi Antonio,

here is a short intor, how one can use the form fields. Assume, we have a form named en:PageWithDate.form, which has its "Template" set to

@_title@
@_text@
@date@
@count@
and its form constraints set to
date:date
count:number
and one fills out two instances, one with e.g. count set to "1", the other one set to "3".

In order to list the entries, one has end-user options and developers options. The simplest end-user function is to use the links offered by xowiki when viewing the form, or one can use the includelet form-usages as show here:

Form usages of PageWithDate.form (without filtering):
{{form-usages -form en:PageWithDate.form -field_names {_title date count} }}

Form usages of PageWithDate.form (with filtering):
{{form-usages -form en:PageWithDate.form -field_names {_title date count} -where {count = 1} }}
When this page is rendered, it show two tables, the first one with all entries, the second one only these having count == 1.

From the developers point of view, one has certainly much more options, which are as well different depending on whether hstore is used or not. Without hstore, filtering of solutions based on the extra "instance attributes" happens in memory (in Tcl), which means that all instances matching other criteria are loaded at the first place into memory before these are tested. For a few hundred tuples this is ok.

When hstore is used, one can use expressions based on the instances attributes directly in sql, leading to very more efficient lookups (with millions of entries). Using hstore or not can't be hidden from the developer. When hstore is activated, also the selection criteria from above is mapped directly to sql (so far, not all possible operators of the where clause are mapped to the hstore counterparts, some operators will require casts from PostgreSQL.).

From the developers point of view, one can certainly use this functionality directly in his scripts, where one can lookup the details from the e.g. form-usages includelet. This includelet does much more as needed often (it obtains form-constraints and form variables from the used form, creates the form-fieds based on the types of the form-constraints, etc. If you simple want to list some data in e.g. a multirow, you can use the script below (written for xowiki in OpenACS 5.9.0) as a starting point. It assumes, the data is stored in an xowiki instance named "xowiki" in a folder named "form-usages" and gets the data either via hstore or from the plain xowiki instance attributes. The script contains as well a little recipe how to setup the instance with hstore. Note that with the presented approach, the raw form-field contents are used (similar to everywhere else in OpenACS). In the general case the types are needed to provide cooked values (as done by the support-functions in xowiki).

For more complex applications, you want to show the data in different situations to different users with different forms. For this kind of application is the xowf package built, which is like FormPages on steroids. We use this for all new development in our systems.

Hope this help
-g

::xowiki::Package initialize -ad_doc {
  This is sample page using form entries

  @author Gustaf Neumann (gustaf.neumann@wu-wien.ac.at)
  @creation-date Nov, 2015
} -parameter {
}

set form //xowiki/form-usages/en:PageWithDate.form
set form_item_id [::xowiki::Weblog instantiate_forms \
		      -forms $form \
		      -package_id $package_id]

if {$form_item_id eq ""} {
    set _ "no such form $form"
} else {
    set _ ""

    #
    # xowiki instance without hstore (probably often the default)
    #
    if {![::xo::dc has_hstore] && [$package_id get_parameter use_hstore 0] == 0} {

	multirow create mytable id name date count
	foreach tuple [::xo::dc list_of_lists get_form_entries {
	    select item_id, name, title, instance_attributes
	    from xowiki_form_instance_item_view
	    where page_template = :form_item_id
	}] {
	    lassign $tuple item_id name title d
	    if {[dict get $d count] ne "1"} continue
	    multirow append mytable $item_id $name [dict get $d date] [dict get $d count]
	}
    } else {
	#
	# xowiki instance with hstore. To setup hstore, one requires:
	#
	# 1) set xowiki package parameter "use_hstore" for instances to 1
	# 2) run in psql: "create extension hstore;"
	# 3) run in psql: "drop table xowiki_form_instance_item_index cascade;"
	# 4) restart server (will rebuild the dropped table and dependent stuff)
	#
	# if you want to upgrade later more xowiki instances to use hstore, one can run
	# ::xowiki::hstore::update_form_instance_item_index selectively on the certain package_ids
	
	multirow create mytable id name date count
	foreach tuple [::xo::dc list_of_lists get_form_entries {
	    select item_id, name, title, instance_attributes
	    from xowiki_form_instance_item_view
	    where page_template = :form_item_id
	    and (hkey->'count') == 1
	}] {
	    lassign $tuple item_id name title d
	    multirow append mytable $item_id $name [dict get $d date] [dict get $d count]
	}
    }
    append _ $tuple \n
}

ns_return 200 text/plain $_
Collapse
8: Re: Help with xowiki (response to 7)
Posted by Antonio Pisano on
Thank you very much, your pointers have been enlightening! Now that I grasp how to come up with a multirow from a FormPage things start to fit in my brain! Digging into form-usages gave me some more insight about how to filter instances, I think I will steal a bit from there! 😊

To better explain my requirements: the application I am writing is going to be a wiki for a good 99%. The remaining 1% is represented by the ability of adding attributes to pages and, most of all, the ability of managing wiki entries in a nice and easy way. In a word: customization.

My company has a long tradition of building effective UIs using "old style" template::list. As antiquate as it may be, this api si very, very mature and allows an easy and declarative approach to listing, while being tightly integrated with adp templating. Features we use the most are of course filtering and pagination.

About pagination in particular, as far as I could see, there doesn't seem to be already some machinery to achieve this using xowiki api. Am I correct?

P.S. xowf is going to be another tool I am going to know more about! ...but first things first!

Collapse
9: Re: Help with xowiki (response to 8)
Posted by Antonio Pisano on
Hello there,

thanks to Gustaf's pointers and some digging, I am starting to understand the internals of xowiki.

Now I am wondering what should be the best way to do this: I have a xowiki instance mounted that serves me as "xowiki engine". Alongside this I have created a package taking care of my particular UI requirements.

My UI is "mobile friendly", that is, my pages are built and shown with big buttons and such. To let xowiki pages come out like this I have customized xowiki's "view" and "edit" template. For "view", I have created a new template called "view-my-application" and set this in xowiki parameters. For "edit", I have customized the standard edit.adp, because I did'nt know how to make it otherwise.

I want my users to create content using my custom UI, but see the result of their work as plain xowiki pages, a regular webpage. Right now, as I have overridden templates, pages are shown in mobile version all the time.

I could make it by putting some if in the templates, but probably there is a smarter way to do this... any clue?

Collapse
10: Re: Help with xowiki (response to 9)
Posted by Gustaf Neumann on
Sorry for being slow with my answers, much to do these days.

Concerning pagination: there are several ways to perform pagination in xowiki, typically using the Table widget, using parameters such as page_size and page_number. Look for e.g. into the weblog-procs or includelets such as "recent" (where pagination is just used for the first page). When it comes to filtering, there is much less support as in the list widget in acs-templating.

For templating xowiki content: When using FormPages, the Form provides you with templates for displaying the content or editing the content. If you want to customize the wiki-menu etc. one can adapt the xowiki templates (xowiki/www/view-*.{adp|tcl}). Just now I've added a small change to let xowiki look as well into the resources directory of the theme. With this change, you should be able to use your own view-default.adp via the theme package, like in:
YOURTHEME/resources/templates/packages/xowiki/www/view-default.adp

Collapse
11: Re: Help with xowiki (response to 10)
Posted by Antonio Pisano on
Thanks Gustaf and don't worry, busy days for everyone.

For filtering and pagination I could come up with something that fits my needs for now, but I will look throughly into other options, as one of my requirements will be to establish some best practices for colleagues if this project goes on.

About templating there is still something I don't get. How can I tell my website "Render this xowiki page with template1" and in a second moment "Now render with template2"?

Right now I can customize my templates globally, but I can't use different templates "case by case". Is there a way to do that?

My scenario is using a back-office template when authoring pages, and a front-office one when seeing pages as regular people.

Collapse
12: Re: Help with xowiki (response to 11)
Posted by Gustaf Neumann on
As before, there are two levels: In order to render a ::xowiki::FormPage with different ::xowiki::Forms, one should use the xowf package. With this the chosen Form depends on the state and optionally by the role of the person viewing the data.

In order to use the different view-*.adp templates, on a per-use case, an approach like the following should work:

   ::xo::Package initialize -url /xowiki
   ::xo::cc set_parameter template_file YOURTEMPLATE
-g
Collapse
13: Re: Help with xowiki (response to 12)
Posted by Antonio Pisano on
That's the trick, thank you!

For reference, ::xo::cc set_parameter template_file YOURTEMPLATE should be called after package initialization, or ::xo::cc instance won't be available.

For my convenience, I have slightly changed index.vuh for xowiki on my instance, so it accepts also a "template_file" parameter. This way I can force the resolver to use the template I want when viewing xowiki pages, case by case. It's a poor man solution, but does exactly what I need and doesn't harm the package whatsoever.

Putting xowf in the mix could do, as I could say: "use this template when logged and another one otherwise", but probably is a bit too much right now. I will get there some other time.

Thanks again!