Owners and Authors field with ACL popup dialog
To fill an Owners and an Authors field on a web form, I needed a popup that allows to pick groups or people from the NAB and roles from the database ACL. Instead of doing a popup window, I decided to show a floating iframe with the dialog. But first I had to build the dialog itself.
The dialog
I made the dialog in a Form element so that I could use a QueryOpen agent and @formulas. For all the options, I use a select tag with optgroups to group the roles, groups and people. A second select tag holds the selected elements. Finally, I've added some buttons for the actions:
<h1 id="title"></h1>
<div>
<div><select id="fSelectList" size="14" multiple="multiple">
<optgroup label="Roles">
<option value="One">One</option>
<option value="Two">Two</option>
<option value="Three">Three</option>
</optgroup>
<optgroup label="Groups">
<option value="Four">Four</option>
<option value="Five">Five</option>
<option value="Six">Six</option>
</optgroup>
<optgroup label="People">
<option value="Ten">Ten</option>
<option value="Twenty">Twenty</option>
<option value="Fourty">Fourty</option>
</optgroup>
</select></div>
<div><button onclick="G.dialog.append()">></button><button onclick="G.dialog.remove()"><</button></div>
<div><select id="fSelected" size="10" multiple="multiple"></select></div>
</div>
<p>
<button onclick="G.dialog.submit()">OK</button>
<button onclick="G.dialog.close()">Cancel</button>
</p>
The JavaScript
I made a singleton G.dialog which holds all the functions. On page load, G.dialog.init() gets the title, the field to fill in and its value from the page the iframe on. The rest of the code processes the actions of the user:
G.dialog={
init:function(){
var m=this,f=m.from=window.top.document,v=m.field=$(G.mid(location.search, 'field=', '&'),f),o=$('fSelected'),s=$('fSelectList'),i
$('title').innerHTML=$$('label',v.parentNode)[0].innerHTML
if(v.value=='')return
v=v.value.split(', ')
for(i=0;i<v.length;i++){m.hideOption(s,v[i]);m.addOption(o,v[i])}
},
addOption:function(a,b){
var y=G.create('option',{text:b,value:b})
try{a.add(y,null)}catch(e){a.add(y)}
},
hideOption:function(a,b,c){
var o=a.options,i,n=o.length
for(i=0;i<n;i++){
if(o[i].value==b){o[i].style.display=c?'':'none';o[i].style.color=c?'':'#ccc';i=n}
}
},
append:function(){
var m=G.dialog,o=$('fSelected'),s=$('fSelectList').options,i
for(i=0; i<s.length;i++){
if(s[i].selected && s[i].style.display==''){G.set(s[i].style,{display:'none',color:'#ccc'})
s[i].selected=false
m.addOption(o,s[i].value)
}
}
},
remove:function(){
var m=G.dialog,o=$('fSelected'),oo=o.options,s=$('fSelectList'),i
for(i=0;i<oo.length;i++){if(oo[i].selected){m.hideOption(s,oo[i].value,true);o.remove(i);i--}}
},
submit:function(){
var m=G.dialog,o=$('fSelected').options,i,v=[]
for(i=0;i<o.length;i++)v.push(o[i].value)
m.field.value=v.join(', ')
m.close()
},
close:function(){var m=G.dialog;$('if-dlg',m.from).style.display='none'}
}
The code to fill the options
I use two computed for display fields to get the lists of groups and people from the NAB. Then I use a QueryOpen agent to fill the content of the fSelectList select box:
a:=@DbColumn(""; "":@GetAddressBooks([FirstOnly]); "($VIMPeople)"; 1);
@If(@IsError(a); @Text(a); @Name([CN]; a))
a:=@DbColumn(""; "":@GetAddressBooks([FirstOnly]); "($VIMGroups)"; 1);
@If(@IsError(a); @Text(a); a)
Sub Initialize
On Error Goto catch
Dim s As New notessession
Dim db As notesdatabase
Dim doc As NotesDocument
Dim out As New stringbuffer(20)
Dim v, i As Integer
Set db=s.CurrentDatabase
Set doc=s.DocumentContext
v=db.ACL.Roles
out.add |<optgroup label="Roles">|
For i=0 To Ubound(v)
out.add |<option value="| & v(i) & |">| & v(i) & |</option>|
Next
out.add |</optgroup><optgroup label="Groups">|
v=doc.dwUserGroups
For i=0 To Ubound(v)
out.add |<option value="| & v(i) & |">| & v(i) & |</option>|
Next
out.add |</optgroup><optgroup label="People">|
v=doc.dwUserNames
For i=0 To Ubound(v)
out.add |<option value="| & v(i) & |">| & v(i) & |</option>|
Next
out.add |</optgroup>|
doc.ReplaceItemValue "dwAclList", out.collapse(NEWLINE)
Goto finally
catch:
doc.ReplaceItemValue "dwAclList", "Error " & Err & " in line " & Erl & ": " & Error$
Resume finally
finally:
End Sub
Adding the popup to the form
The popup button and the iframe
<li>
<label for="fOwnerList">Owners: </label>
<input id="fOwnerList" name="OwnerList" value="[Admin]">
<input type="button" class="small" onclick="G.dialog('acl','fOwnerList')" value="..." />
</li>
<li>
<label for="fAuthorList">Authors: </label>
<input id="fAuthorList" name="AuthorList" value="Axi Sitebuilder Managers, d-works-people">
<input type="button" class="small" onclick="G.dialog('acl','fAuthorList')" value="..." />
</li>
<iframe src="" id="if-dlg" frameborder="0"></iframe>
The CSS for the iframe:
#if-dlg{width:470px;height:270px;border:solid 1px #ccc;position:absolute;display:none}
And finally, the JavaScript to open the popup, centered in the window:
G.dialog=function(a,b){
var w=window,dd=document.documentElement,o=$('if-dlg'),os=o.style,tp,lf
os.display='block'
tp=parseInt((w.pageYOffset||dd.scrollTop)+((w.innerHeight||dd.clientHeight)-o.offsetHeight)/2)+'px'
lf=parseInt((w.pageXOffset||dd.scrollLeft)+((w.innerWidth||dd.clientWidth)-o.offsetWidth)/2)+'px'
G.set(os,{top:tp,left:lf})
o.src=G.base+'.dlg-'+a+"?readform&field="+b
}
Screenshot

Some things are not so obvious to achieve. This simple dialog box took me 12 hours. And yes, I know it is not very scalable.
Comments
07/04/2008 03:59:41 AM, Jean Daigle
Hi, your code is interesting but I am very confused about how to apply it in my environment. You seem to be saying that some of the code goes in a Form - as pass-thru HTML? And then you say that you have a QueryOpen agent - how do you call this and from where?
Thanks,
Jean A beginner programmer with LS
To add a comment, log in or register as new user. It's free and safe.