Read-Only Editable Rich Text Fields
Just recently I've worked on a couple of sites that needed sign-up forms for new users. You know the kind - enter your details, along with a username and password, before agreeing to some T&Cs and submitting the request. Nothing ground-breaking really.
However, there's a problem with these forms — the legalese text of the terms and conditions. You know what they'e like; going on and on and on endlessly. With this in mind I ended up wondering what was the best to way to store them in our Form?
- Enter the text straight on to the form.
- Store the text in a configuration document and fetch it via an @DBLookup.
The first option isn't really suitable as the text changes and, as we all know, design and data should never be mixed. The second option is better, but it limits the amount of text the legal department can use. Probably a good thing but they just won't have it!
What we need is a way to store as much text as they can produce and import it in to the sign-up form. To do this we need to store the text in a Rich Text field. How so?
What I've come up with is a elegant hack to import some read-only Rich Text in to a new form in edit mode. The rich text is stored in a separate document. First thing to do is fetch it using the WQO agent:
Set vContractsView = vThisDatabase.GetView("Agreements") Set vContractDocument = vContractsView.GetFirstDocument Set rtitem = vContractDocument.GetFirstItem( "Body") Call rtitem.CopyItemToDocument( vWebDocument, "Agreement")
This copies the Body field from the contract document to the Agreement field on our signup form. Now, the Agreement field is Rich Text, which, by default, will appear as a TEXTAREA element containing unformatted text. Although the form is in edit mode we want the field to be in read mode.
My first attempt to make it read only was to make the Agreement field computed, referencing itself as the computed value. This doesn't seem to work in combination with the WQO LotusScript though (anybody know why?). Instead I turned to a design element I've not used for about 6 years — the Controlled Access Section.
Notice the Agreement field is inside a (untitled) section. The access formula for this section is "no-one", meaning that only a user called "no-one" can edit the fields inside it. Assuming that's not the user's name then this makes the field appear as read-mode text. Et voila - limitless amounts of user-configured rich text on a form.
Here's a Demo Form., which you can download here.
Update: I added a second demo form to the database which demonstrate's Peter LaComb's more elegant approach, described in the comments below (basically you delete the computed RT field using the WQO agent, before creating a new one).
I like that. I've never used Controled Access sections. Clever you.
instead of the hack, I've been using a simple dblookup in the rich text field, with good results so far
the rich text field would be computed (so no-one can edit), and the dblookup would insert the rt on opening the form. It has been working fine so far.
I had to remember to remove the 'licencetext' field afterwards ofcourse.
Does your approach also keep the agreement field saved, or does it remove it somehow?
Manu. But that's limited by the 64kb thing is it not?
The Agreement field would have to be re-added by a WQS agent if it had to be saved with the signup document.
Couldnt you get it using an Ajax call, return the rich text html and update the <div id="agreement"> tag with it. Then you could get it on demand if the user wanted it (or get it always and just hide / show) and if they wanted to print it then the style sheet print could take over...
Jake,
I believe the solution is either marking the field on the form as pass-through, or applying the passthrough style to the item as you populate it - I do this to put multiple (albeit small) views on a form:
If doc.HasItem("comments") Then
Call doc.RemoveItem("comments")
End If
Set dest = doc.CreateRichTextItem("comments")
Set vec = view.GetAllEntriesByKey(doc.UniversalID)
Set ve = vec.GetFirstEntry
While Not (ve Is Nothing)
Set tdoc = ve.Document
Set src = tdoc.GetFirstItem("body")
Set nn = New NotesName(ve.Document.myCreator(0))
Call dest.AppendStyle(myPassThroughStyle)
Call dest.AppendText(|<div class="comment"><b>|)
Call dest.AppendText(nn.Abbreviated & " - " & ve.Document.Created)
Call dest.AppendText(|</b><br /><br />|)
Call dest.AppendRTItem(src)
Call dest.AppendText(|</div>|)
Set ve = vec.GetNextEntry(ve)
Wend
Alastair. Yes, you could. Sounds a bit like using Ajax for Ajax's sake to me though. Might be nice if users rarely want to see the T&Cs to only fetch it on demand.
In my case the site needed to be "accessible" so this wasn't an option.
Peter. Marking RT fields as Passthru isn't exactly foolproof in my experience.
Is the code you posted for a document in read mode or does it append to a computed RT field?
Another nicity would be to add surrounding passthru html so the user doesn't have to scroll if they aren't going to read the whole thing anyway.
<textarea cols=80 rows=20 readonly>
lic text
</textarea>
Or, if you wanted formatting within the scrollable box, use a div with some CSS to mimic a readonly text area.
<div style="width:500px;height:250px;overflow:auto; border: 1px solid #000">
lic txt
</div>
I think, you should be able to have a computed RTF, but instead of a @DBlookup you could use @GetDocField with the UNID of the T6C document. This should eliminate the 64K problem, but I could be wrong.
Jake,
That works in both edit mode and read mode.
I haven't had problems with it yet, but I've only been using it for a few months.
The only way I could see it being a problem is if someone put a mix of passthrough and non-passthrough text into the field - I have no Idea how that would be handled. I'm no RT expert, but I'd have to assume there is some way to apply the passthrough style to the entire field (hopefully easily).
Peter Leugner - @getdocfield is still formula, so it should still fail on >64K of data.
err - I wasn't clear in my response - as posted, it replaces a computed RT field in either read or edit mode (done in webqueryopen)
Peter Leugner. That kind of works, but doesn't. It returns the text in the first Body field. Notes splits large RT fields in to multiple smaller ones on the document, each with the same name and "duplicate ID" values. So, it doesn't get round the size limitation.
Anyway, you'd have to know the UNID of the document ;o)
Other Peter. Thanks I'll take a look see.
Peter LaComb. That works. Cool! A much more elegant hack than mine. I'll remember this for next time I get this request from a client. In fact I'll add a second form to the demo db and update the download for people yet to join the thread...
I had to do this a couple of years ago.
Instead of using WQO - just get the richtext field direct from the stored agreement configuration document using it's UNID which can also be lookup up to the agreement title, to allow for different agreements, or policies.
[formula code in Computed Rich Text Field]
DOC_UNID = @DbLookup("": "nocache"; "":""; "Lookup";AgreementName ; 2);
@GetDocField( DOC_UNID ; "rt_Agreement" );
© notes411.com
Andy. As mentioned above, this is size-restricted to first chunk of the rich text field.
@Andy,
I see you have a copyright symbol next to notes411.com and I assume that your sample code isn't copyrighted, just the name notes411.com right? :-)
Peter LaComb and Jake. We have been using a similar method for a few years now (since Aug. 2003) and it has not broken, so there should be no worries.
Unlike Peter's solution, we have this computed rich text field surrounded by pass-thru HTML (open and closing element), so we don't need to set the style. We use an WQO agent to populate this RT field and it displays as formatted content.
actually it does handle more than 64K in read mode.
just tested it...
but you still need to add the HTML for the Form, handler and a WQS to record the richtext in the agreement.
and Bruce, I was just testing the ability to submit random characters ( no copyright )
;-)
andy
acornes.com
Following on from Alastair's suggestion take a look at ...
{Link}
..and load the page dynamically, linking in the source html pages ( including the read-only rich text field with it's web form )
just a thought but it may work ok..
:-)
Doug - That's good to know. Thanks.
Jake, this may cause other problems depending on the rest of your form's design, but the easiest way I've found to prepopulate a computed rich text field from another document is to enable the "inherit values from selected document" setting. As I'm sure you know, this setting isn't limited to true response documents; if you can easily retrieve the configuration document's UNID, set the computed RTF to the name of the config doc's RTF, then append "&ParentUNID=...." to the OpenForm portion of the URL. This causes the field on the new document to default to the existing value on the configuration document, regardless of size. As I mentioned, however, this can cause other issues: namely, if you have other fields with default or computed values that reference field names, it can cause those formulas to evaluate incorrectly. But I've used this approach often with fairly consistent success.
Doug. Based on past experience I'd be very wary of marking a rich text field as passthru (especially when using tricks like surrounding it with ] brackets).
Andy. Doesn't work for me. There's a definite trimming happening. Is your RT field split in the document?
Have done a similar thing with copying the rich text item from another doc before. Did the read only bit slightly differently tho...just set the readonly attribute in the html attributes for the rt field and off you go. e.g. you may have "width=\"200\" height=\"100\" readonly=\"readonly\"" in the attributes which will give a readonly scrollable textarea with all of the text in it while leaving the rest of the form as editable.
Jake: Thanks for the warning.
Previously surrounding rich text fields with square brackets was flaky, but since R5, having actual pass-thru (using Text -- Pass-Thru HTML) surrounding a rich text field has been solid for us.
Jake
Any reason that you can't simply create a separate doc for the text, a trivially simple one RT field would do, and then display via an IFRAME on your form ??
Text would be end user editable and under any security control necessary.
No agents, no fuss, no 64k worries, no nothing.
???
Ron
Jake, you are right, it is truncating when I try to populate a new document field in a new document - my mistake was i was testing it in a "response" document to the document containing the actual agreement, and it was "Inheriting" the rich text field, and no longer looking it up.
Could this be another solution ?
cheers
andy
Really useful!!!
Thank you Jake!
Tip to stop the section to confuse Notes users: set the hide-when properties of the controlled access section to be hidden (I did that by checking all options in the subsection "Hide paragraph when document is")
Then, make sure there NO hide whens on the rich text field.
Also, in the autoexpand tab, I set all options to autoexpand for both Editord and non-Editors.
Result: the access control still works, but the section title, and more important, the twistie, are hidden. So the user is not confused about the extra UI element. Using the menu, Edit:Collapse all Sections, does not affect Controlled Accesss Sections prepped like this.
Lars Berntrop-Bos