File: mod.html

package info (click to toggle)
moodle 1.6.3-2%2Betch3
  • links: PTS
  • area: main
  • in suites: etch
  • size: 37,172 kB
  • ctags: 51,688
  • sloc: php: 231,916; sql: 5,631; xml: 2,688; sh: 1,185; perl: 638; makefile: 48; pascal: 36
file content (777 lines) | stat: -rw-r--r-- 33,768 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
<!-- This page defines the form to create or edit an instance of this module -->
<!-- It is used from /course/mod.php.  The whole instance is available as $form. -->

<!--
TODO: display proper message when no sequences are received
-->

<?php

include_once($CFG->dirroot.'/mod/lams/constants.php');

if (!isset($form->name)) {
    $form->name = '';
}
if (!isset($form->introduction)) {
    $form->introduction = '';
}
if (!isset($form->learning_session_id)) {
    $form->learning_session_id = '';
}

if (!isset($form->create_sequence_url)) {
    $datetime =    date("F d,Y g:i a");
    $plaintext = trim($datetime).trim($USER->username).trim($LAMSCONSTANTS->author_method).trim($CFG->lams_serverid).trim($CFG->lams_serverkey);
    $hash = sha1(strtolower($plaintext));
    $form->create_sequence_url = $CFG->lams_serverurl.$LAMSCONSTANTS->login_request.
        '?'.$LAMSCONSTANTS->param_uid.'='.$USER->username.
        '&'.$LAMSCONSTANTS->param_method.'='.$LAMSCONSTANTS->author_method.
        '&'.$LAMSCONSTANTS->param_timestamp.'='.urlencode($datetime).
        '&'.$LAMSCONSTANTS->param_serverid.'='.$CFG->lams_serverid.
        '&'.$LAMSCONSTANTS->param_hash.'='.$hash.
        '&'.$LAMSCONSTANTS->param_courseid.'='.$form->course;
}
?>

<form name="form" method="post" action="mod.php" onSubmit="disableSumbit(this);">
<center>
<span id="message"><P>Please wait .......</P></span>
<table cellpadding="5">
<tr valign=top>
<td align=right><b><?php print_string("workspace", "lams") ?>:</b></td>
<td>
<select id="workspace" name="workspace"></select>
</td>
</tr>
<tr>
<td align="right"><b><?php  print_string("sequence","lams") ?>:</b></td>
<td>
<select id="sequence" name="sequence"></select>
</td>
</tr>
<tr>
<td align="right"><b><?php  print_string("name") ?>:</b></td>
<td>
<input type="text" id="name" name="name" size="30">
</td>
</tr>
<td align=right><p><b><?php print_string("introduction", "lams") ?>:</b></p>
<br />
<font size="1">
<?php
if ($usehtmleditor) {
    helpbutton("richtext", get_string("helprichtext"), "moodle", true, true);
} else {
    helpbutton("text", get_string("helptext"), "moodle", true, true);
    echo '<br />';
    emoticonhelpbutton("form", "introduction");
    echo '<br />';
}
?>
<br />
</font>
</td>
<td>
<?php
print_textarea($usehtmleditor, 20, 50, 680, 400, "introduction", $form->introduction);
?>
</td>
</tr>

<!-- The following line for Moodle 1.5 prints the visibility setting form element -->
<!-- <?php print_visible_setting($form); ?> -->
<!-- and if your module uses groups you would also have -->
<!-- ?php print_groupmode_setting($form); ? -->

</table>
<input type="hidden" name="learning_session_id"/>
<input type="hidden" name="create_sequence_url" id="create_sequence_url"/>
<input type="submit" id="save" name="save" value="<?php print_string("useSequence","lams") ?>" onClick="return validate();">
<input type="button" id="edit" name"edit" value="<?php print_string("editSequence","lams") ?>" onClick="openAuthor(<?php echo "'".$form->create_sequence_url."&".$LAMSCONSTANTS->param_ldid."=".$form->sequence."'";?>);">
<input type="button" id="create" name="create" value="<?php print_string("createSequence","lams") ?>" onClick="openAuthor(<?php echo "'".$form->create_sequence_url."'";?>);">
<input type="button" id="refresh" name="refresh" value="<?php print_string("refreshSequenceList","lams")?>" onclick="refreshLists();">
<input type="submit" id="cancel" name=cancel value="<?php  print_string("cancel") ?>">


<!-- These hidden variables are always the same -->
<input type="hidden" name=course        value="<?php  p($form->course) ?>" />
<input type="hidden" name="sesskey"     value="<?php  p($form->sesskey) ?>" />
<input type="hidden" name=coursemodule  value="<?php  p($form->coursemodule) ?>" />
<input type="hidden" name=section       value="<?php  p($form->section) ?>" />
<input type="hidden" name=module        value="<?php  p($form->module) ?>" />
<input type="hidden" name=modulename    value="<?php  p($form->modulename) ?>" />
<input type="hidden" name=instance      value="<?php  p($form->instance) ?>" />
<input type="hidden" name=mode          value="<?php  p($form->mode) ?>" />
</center>

</form>

<script language="JavaScript" type="text/javascript">
<!--

function validate(){
    workspaceObj = document.getElementById("workspace");
    if (workspaceObj.options.length == 0){
        alert("No workspace was returned from LAMS server! You may try refreshing sequence list.\nIf you still get the same problem, probably you have to cancel this activity.");
        return false;
    }
    sequenceObj = document.getElementById("sequence");
    if(sequenceObj.options.length == 0){
        alert("No sequence was returned from LAMS server! You may try refreshing sequence list.\nIf you still get the same problem, probably you have to cancel this activity.");
        return false;
    }
    if(trim(document.getElementById("name").value).length==0){
        alert("You have to specify the activity name to proceed.");
        return false;
    }
    return true;
}

function trim(trim_value){
    if(trim_value.length < 1){
        return"";
    }
    trim_value = rTrim(trim_value);
    trim_value = lTrim(trim_value);
    return trim_value;
} //End Function

function rTrim(trim_value){
    var w_space = String.fromCharCode(32);
    var v_length = trim_value.length;
    var strTemp = "";
    if(v_length < 0){
        return"";
    }
    var iTemp = v_length -1;

    while(iTemp > -1){
        if(trim_value.charAt(iTemp) != w_space){
            strTemp = trim_value.substring(0,iTemp +1);
            break;
        }
        iTemp = iTemp-1;
    } //End While
    return strTemp;
} //End Function

function lTrim(trim_value){
    var w_space = String.fromCharCode(32);
    if(v_length < 1){
        return"";
    }
    var v_length = trim_value.length;
    var strTemp = "";

    var iTemp = 0;

    while(iTemp < v_length){
        if(trim_value.charAt(iTemp) != w_space){
            strTemp = trim_value.substring(iTemp,v_length);
            break;
        }
        iTemp = iTemp + 1;
    } //End While
    return strTemp;
} //End Function

function disableSubmit(dform) {
    if (document.getElementById) {
        for (var sch = 0; sch < dform.length; sch++) {
            if (dform.elements[sch].type.toLowerCase() == "submit") dform.elements[sch].disabled = true;
        }
    }
    return true;
}

function enableSubmit(dform) {
    if (document.getElementById) {
        for (var sch = 0; sch < dform.length; sch++) {
            if (dform.elements[sch].type.toLowerCase() == "submit") dform.elements[sch].disabled = false;
        }
    }
    return true;
}

var authorWin = null;
function openAuthor(url){
    //alert(url);
    if(authorWin && authorWin.open && !authorWin.closed){
        authorWin.document.location = url;
        authorWin.focus();
    }else{
        authorWin = window.open(url);
        authorWin.focus();
    }
}


var req;
/**
 * This function is to initialize elements' status and refresh workspace and sequence lists
 */
function refreshLists(){
    document.getElementById("message").innerHTML = "<P>Please wait .......</P>";
    disableSubmit(document.forms[0]);
    document.getElementById("create").disabled = true;
    document.getElementById("edit").disabled = true;
    document.getElementById("refresh").disabled = true;

    wsSelectObj = document.getElementById("workspace");
    wsSelectObj.options.length = 0; //remove all options
    wsSelectObj.options[0] = new Option("Loading...", "Loading...");
    wsSelectObj.disabled = true;

    seqSelectObj = document.getElementById("sequence");
    seqSelectObj.options.length = 0; //remove all options

    //clear the DynamicOptionList
    dol = new DynamicOptionList("workspace","sequence");
    dol.setFormName("form");

    url = "../mod/lams/list.php?courseid="+document.form.course.value;
    if (window.XMLHttpRequest) { // Non-IE browsers
        req = new XMLHttpRequest();
        req.onreadystatechange = processStateChange;
        try {
            req.open("GET", url, true);
        } catch (e) {
            alert(e);
        }
        req.send(null);
    } else if (window.ActiveXObject) { // IE
        req = new ActiveXObject("Microsoft.XMLHTTP");
        if (req) {
            req.onreadystatechange = processStateChange;
            req.open("GET", url, true);
            req.send();
        }
    }
}

function processStateChange() {
    if (req.readyState == 4) { // Complete
        var wsSelectObj = document.getElementById("workspace");
        wsSelectObj.options.length = 0; //clear the workspace list
        wsSelectObj.disabled = false;
        enableSubmit(document.forms[0]);
        document.getElementById("create").disabled = false;
        document.getElementById("edit").disabled = false;
        document.getElementById("refresh").disabled = false;
        if (req.status == 200) { // OK response
            var res = req.responseText.replace(/^\s*|\s*$/g,""); //get trimed result
            var seqlistStr = res.split(':'); //seperate each set of {sid, workspace,sequence}
            var seqlist = new Array();

            var workspaceList = new Object();

            //pass the response and construct the list again
            for(var i=0; i<seqlistStr.length; i++){
                var sws =  seqlistStr[i].split(',');
                if(sws.length == 3){
                    var sid = sws[0];
                    var workspace = sws[1];
                    var sequence = sws[2];

                    if(workspaceList[workspace] == null){
                        //set workspace as keys in workspaceList (kind of like a map)
                        //therefore duplicated workspaces will be ignored
                        workspaceList[workspace] = 1; //insert workspace as a key

                        //insert workspace into workspace list
                        wsSelectObj.options[wsSelectObj.length] = new Option(workspace,workspace);
                    }

                    //insert sequence dependency into DynamicOptionList
                    dol.forValue(workspace).addOptionsTextValue(sequence,sid);
                }
            }
            initDynamicOptionLists(); //construct the list
            document.getElementById("message").innerHTML =
                "<p>Select an existing sequence or create a new sequence.</p>";
        }else if(req.status == 504){//gateway timeout. probabaly LAMS server is not available.
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">It seems the LAMS server is not available!<BR> Please contact your administrator.</h4></td></tr></table>';
        }else if(req.status == 401){//AuthenticationException thrown by LAMS server.
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">This moodle server is not authenticated by LAMS!<BR> Please contact your administrator.</h4></td></tr></table>';
        }else if(req.status == 502){//Unknow exception thrown by LAMS server
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">An unexpected error returned from LAMS server:'+req.responseText+'! Please contact your administrator.</h4></td></tr></table>';
        }else if(req.status == 417){//ServerNotFound exception thrown by LAMS server
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">This moodle server has not registered in LAMS!<BR> Please contact your administrator.</h4></td></tr></table>';
        }else if(req.status == 402){//All LAMS module settings have not not been set up
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">All the LAMS module settings have not been set up!<BR> Please contact your administrator.</h4></td></tr></table>';
        }else{//this error should come from moodle server itself
            document.getElementById("message").innerHTML =
                '<table align="center" width="57%"  class="noticebox" border="0" cellpadding="15" cellspacing="0"><tr><td bgcolor="#FFAAAA" class="noticeboxcontent"><h4   class="main">It should be a moodle server error:'+req.status + ' ' + req.statusText+'! Please contact your administrator.</h4></td></tr></table>';
        }
    }
}

var dynamicOptionListCount=0;
var dynamicOptionListObjects = new Array();

// Init call to setup lists after page load. One call to this function sets up all lists.
function initDynamicOptionLists() {
    // init each DynamicOptionList object
    for (var i=0; i<dynamicOptionListObjects.length; i++) {
        var dol = dynamicOptionListObjects[i];

        // Find the form associated with this list
        if (dol.formName!=null) {
            dol.form = document.forms[dol.formName];
        }
        else if (dol.formIndex!=null) {
            dol.form = document.forms[dol.formIndex];
        }
        else {
            // Form wasn't set manually, so go find it!
            // Search for the first form element name in the lists
            var name = dol.fieldNames[0][0];
            for (var f=0; f<document.forms.length; f++) {
                if (typeof(document.forms[f][name])!="undefined") {
                    dol.form = document.forms[f];
                    break;
                }
            }
            if (dol.form==null) {
                alert("ERROR: Couldn't find form element "+name+" in any form on the page! Init aborted"); return;
            }
        }

        // Form is found, now set the onchange attributes of each dependent select box
        for (var j=0; j<dol.fieldNames.length; j++) {
            // For each set of field names...
            for (var k=0; k<dol.fieldNames[j].length-1; k++) {
                // For each field in the set...
                var selObj = dol.form[dol.fieldNames[j][k]];
                if (typeof(selObj)=="undefined") { alert("Select box named "+dol.fieldNames[j][k]+" could not be found in the form. Init aborted"); return; }
                // Map the HTML options in the first select into the options we created
                if (k==0) {
                    if (selObj.options!=null) {
                        for (l=0; l<selObj.options.length; l++) {
                            var sopt = selObj.options[l];
                            var m = dol.findMatchingOptionInArray(dol.options,sopt.text,sopt.value,false);
                            if (m!=null) {
                                var reselectForNN6 = sopt.selected;
                                var m2 = new Option(sopt.text, sopt.value, sopt.defaultSelected, sopt.selected);
                                m2.selected = sopt.selected; // For some reason I need to do this to make NN4 happy
                                m2.defaultSelected = sopt.defaultSelected;
                                m2.DOLOption = m;
                                selObj.options[l] = m2;
                                selObj.options[l].selected = reselectForNN6; // Reselect this option for NN6 to be happy. Yuck.
                            }
                        }
                    }
                }
                if (selObj.onchange==null) {
                    // We only modify the onChange attribute if it's empty! Otherwise do it yourself in your source!
                    selObj.onchange = new Function("dynamicOptionListObjects["+dol.index+"].change(this)");
                }
            }
        }
    }
    // Set the preselectd options on page load
    resetDynamicOptionLists();
}

// This function populates lists with the preselected values.
// It's pulled out into a separate function so it can be hooked into a 'reset' button on a form
// Optionally passed a form object which should be the only form reset
function resetDynamicOptionLists(theform) {
    // reset each DynamicOptionList object
    for (var i=0; i<dynamicOptionListObjects.length; i++) {
        var dol = dynamicOptionListObjects[i];
        if (typeof(theform)=="undefined" || theform==null || theform==dol.form) {
            for (var j=0; j<dol.fieldNames.length; j++) {
                dol.change(dol.form[dol.fieldNames[j][0]],true); // Second argument says to use preselected values rather than default values
            }
        }
    }
}

// An object to represent an Option() but just for data-holding
function DOLOption(text,value,defaultSelected,selected) {
    this.text = text;
    this.value = value;
    this.defaultSelected = defaultSelected;
    this.selected = selected;
    this.options = new Array(); // To hold sub-options
    return this;
}

// DynamicOptionList CONSTRUCTOR
function DynamicOptionList() {
    this.form = null;// The form this list belongs to
    this.options = new Array();// Holds the options of dependent lists
    this.longestString = new Array();// Longest string that is currently a potential option (for Netscape)
    this.numberOfOptions = new Array();// The total number of options that might be displayed, to build dummy options (for Netscape)
    this.currentNode = null;// The current node that has been selected with forValue() or forText()
    this.currentField = null;// The current field that is selected to be used for setValue()
    this.currentNodeDepth = 0;// How far down the tree the currentNode is
    this.fieldNames = new Array();// Lists of dependent fields which use this object
    this.formIndex = null;// The index of the form to associate with this list
    this.formName = null;// The name of the form to associate with this list
    this.fieldListIndexes = new Object();// Hold the field lists index where fields exist
    this.fieldIndexes = new Object();// Hold the index within the list where fields exist
    this.selectFirstOption = true;// Whether or not to select the first option by default if no options are default or preselected, otherwise set the selectedIndex = -1
    this.numberOfOptions = new Array();// Store the max number of options for a given option list
    this.longestString = new Array();// Store the longest possible string
    this.values = new Object(); // Will hold the preselected values for fields, by field name

    // Method mappings
    this.forValue = DOL_forValue;
    this.forText = DOL_forText;
    this.forField = DOL_forField;
    this.forX = DOL_forX;
    this.addOptions = DOL_addOptions;
    this.addOptionsTextValue = DOL_addOptionsTextValue;
    this.setDefaultOptions = DOL_setDefaultOptions;
    this.setValues = DOL_setValues;
    this.setValue = DOL_setValues;
    this.setFormIndex = DOL_setFormIndex;
    this.setFormName = DOL_setFormName;
    this.printOptions = DOL_printOptions;
    this.addDependentFields = DOL_addDependentFields;
    this.change = DOL_change;
    this.child = DOL_child;
    this.selectChildOptions = DOL_selectChildOptions;
    this.populateChild = DOL_populateChild;
    this.change = DOL_change;
    this.addNewOptionToList = DOL_addNewOptionToList;
    this.findMatchingOptionInArray = DOL_findMatchingOptionInArray;

    // Optionally pass in the dependent field names
    if (arguments.length > 0) {
        // Process arguments and add dependency groups
        for (var i=0; i<arguments.length; i++) {
            this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
            this.fieldIndexes[arguments[i].toString()] = i;
        }
        this.fieldNames[this.fieldNames.length] = arguments;
    }

    // Add this object to the global array of dynamicoptionlist objects
    this.index = window.dynamicOptionListCount++;
    window["dynamicOptionListObjects"][this.index] = this;
}

// Given an array of Option objects, search for an existing option that matches value, text, or both
function DOL_findMatchingOptionInArray(a,text,value,exactMatchRequired) {
    if (a==null || typeof(a)=="undefined") { return null; }
    var value_match = null; // Whether or not a value has been matched
    var text_match = null; // Whether or not a text has been matched
    for (var i=0; i<a.length; i++) {
        var opt = a[i];
        // If both value and text match, return it right away
        if (opt.value==value && opt.text==text) { return opt; }
        if (!exactMatchRequired) {
            // If value matches, store it until we complete scanning the list
            if (value_match==null && value!=null && opt.value==value) {
                value_match = opt;
            }
            // If text matches, store it for later
            if (text_match==null && text!=null && opt.text==text) {
                text_match = opt;
            }
        }
    }
    return (value_match!=null)?value_match:text_match;
}

// Util function used by forValue and forText
function DOL_forX(s,type) {
    if (this.currentNode==null) { this.currentNodeDepth=0; }
    var useNode = (this.currentNode==null)?this:this.currentNode;
    var o = this.findMatchingOptionInArray(useNode["options"],(type=="text")?s:null,(type=="value")?s:null,false);
    if (o==null) {
        o = new DOLOption(null,null,false,false);
        o[type] = s;
        useNode.options[useNode.options.length] = o;
    }
    this.currentNode = o;
    this.currentNodeDepth++;
    return this;
}

// Set the portion of the list structure that is to be used by a later operation like addOptions
function DOL_forValue(s) { return this.forX(s,"value"); }

// Set the portion of the list structure that is to be used by a later operation like addOptions
function DOL_forText(s) { return this.forX(s,"text"); }

// Set the field to be used for setValue() calls
function DOL_forField(f) { this.currentField = f; return this; }

// Create and add an option to a list, avoiding duplicates
function DOL_addNewOptionToList(a, text, value, defaultSelected) {
    var o = new DOLOption(text,value,defaultSelected,false);
    // Add the option to the array
    if (a==null) { a = new Array(); }
    for (var i=0; i<a.length; i++) {
        if (a[i].text==o.text && a[i].value==o.value) {
            if (o.selected) {
                a[i].selected=true;
            }
            if (o.defaultSelected) {
                a[i].defaultSelected = true;
            }
            return a;
        }
    }
    a[a.length] = o;
}

// Add sub-options to the currently-selected node, with the same text and value for each option
function DOL_addOptions() {
    if (this.currentNode==null) { this.currentNode = this; }
    if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
    for (var i=0; i<arguments.length; i++) {
        var text = arguments[i];
        this.addNewOptionToList(this.currentNode.options,text,text,false);
        if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
            this.numberOfOptions[this.currentNodeDepth]=0;
        }
        if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
            this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
        }
        if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
            this.longestString[this.currentNodeDepth] = text;
        }
    }
    this.currentNode = null;
    this.currentNodeDepth = 0;
}

// Add sub-options to the currently-selected node, specifying separate text and values for each option
function DOL_addOptionsTextValue() {
    if (this.currentNode==null) { this.currentNode = this; }
    if (this.currentNode["options"] == null) { this.currentNode["options"] = new Array(); }
    for (var i=0; i<arguments.length; i++) {
        var text = arguments[i++];
        var value = arguments[i];
        this.addNewOptionToList(this.currentNode.options,text,value,false);
        if (typeof(this.numberOfOptions[this.currentNodeDepth])=="undefined") {
            this.numberOfOptions[this.currentNodeDepth]=0;
        }
        if (this.currentNode.options.length > this.numberOfOptions[this.currentNodeDepth]) {
            this.numberOfOptions[this.currentNodeDepth] = this.currentNode.options.length;
        }
        if (typeof(this.longestString[this.currentNodeDepth])=="undefined" || (text.length > this.longestString[this.currentNodeDepth].length)) {
            this.longestString[this.currentNodeDepth] = text;
        }
    }
    this.currentNode = null;
    this.currentNodeDepth = 0;
}

// Find the first dependent list of a select box
// If it's the last list in a chain, return null because there are no children
function DOL_child(obj) {
    var listIndex = this.fieldListIndexes[obj.name];
    var index = this.fieldIndexes[obj.name];
    if (index < (this.fieldNames[listIndex].length-1)) {
        return this.form[this.fieldNames[listIndex][index+1]];
    }
    return null;
}

// Set the options which should be selected by default for a certain value in the parent
function DOL_setDefaultOptions() {
    if (this.currentNode==null) { this.currentNode = this; }
    for (var i=0; i<arguments.length; i++) {
        var o = this.findMatchingOptionInArray(this.currentNode.options,null,arguments[i],false);
        if (o!=null) {
            o.defaultSelected = true;
        }
    }
    this.currentNode = null;
}

// Set the options which should be selected when the page loads. This is different than the default value and ONLY applies when the page LOADS
function DOL_setValues() {
    if (this.currentField==null) {
        alert("Can't call setValues() without using forField() first!");
        return;
    }
    if (typeof(this.values[this.currentField])=="undefined") {
        this.values[this.currentField] = new Object();
    }
    for (var i=0; i<arguments.length; i++) {
        this.values[this.currentField][arguments[i]] = true;
    }
    this.currentField = null;
}

// Manually set the form for the object using an index
function DOL_setFormIndex(i) {
    this.formIndex = i;
}

// Manually set the form for the object using a form name
function DOL_setFormName(n) {
    this.formName = n;
}

// Print blank <option> objects for Netscape4, since it refuses to grow or shrink select boxes for new options
function DOL_printOptions(name) {
    // Only need to write out "dummy" options for Netscape4
    if ((navigator.appName == 'Netscape') && (parseInt(navigator.appVersion) <= 4)){
        var index = this.fieldIndexes[name];
        var ret = "";
        if (typeof(this.numberOfOptions[index])!="undefined") {
            for (var i=0; i<this.numberOfOptions[index]; i++) {
                ret += "<OPTION>";
            }
        }
        ret += "<OPTION>";
        if (typeof(this.longestString[index])!="undefined") {
            for (var i=0; i<this.longestString[index].length; i++) {
                ret += "_";
            }
        }
        document.writeln(ret);
    }
}

// Add a list of field names which use this option-mapping object.
// A single mapping object may be used by multiple sets of fields
function DOL_addDependentFields() {
    for (var i=0; i<arguments.length; i++) {
        this.fieldListIndexes[arguments[i].toString()] = this.fieldNames.length;
        this.fieldIndexes[arguments[i].toString()] = i;
    }
    this.fieldNames[this.fieldNames.length] = arguments;
}

// Called when a parent select box is changed. It populates its direct child, then calls change on the child object to continue the population.
function DOL_change(obj, usePreselected) {
    if (usePreselected==null || typeof(usePreselected)=="undefined") { usePreselected = false; }
    var changedListIndex = this.fieldListIndexes[obj.name];
    var changedIndex = this.fieldIndexes[obj.name];
    var child = this.child(obj);
    if (child == null) { return; } // No child, no need to continue
    if (obj.type == "select-one") {
        // Treat single-select differently so we don't have to scan the entire select list, which could potentially speed things up
        if (child.options!=null) {
            child.options.length=0; // Erase all the options from the child so we can re-populate
        }
        if (obj.options!=null && obj.options.length>0 && obj.selectedIndex>=0) {
            var o = obj.options[obj.selectedIndex];
            this.populateChild(o.DOLOption,child,usePreselected);
            this.selectChildOptions(child,usePreselected);
        }
    }
    else if (obj.type == "select-multiple") {
        // For each selected value in the parent, find the options to fill in for this list
        // Loop through the child list and keep track of options that are currently selected
        var currentlySelectedOptions = new Array();
        if (!usePreselected) {
            for (var i=0; i<child.options.length; i++) {
                var co = child.options[i];
                if (co.selected) {
                    this.addNewOptionToList(currentlySelectedOptions, co.text, co.value, co.defaultSelected);
                }
            }
        }
        child.options.length=0;
        if (obj.options!=null) {
            var obj_o = obj.options;
            // For each selected option in the parent...
            for (var i=0; i<obj_o.length; i++) {
                if (obj_o[i].selected) {
                    // if option is selected, add its children to the list
                    this.populateChild(obj_o[i].DOLOption,child,usePreselected);
                }
            }
            // Now go through and re-select any options which were selected before
            var atLeastOneSelected = false;
            if (!usePreselected) {
                for (var i=0; i<child.options.length; i++) {
                    var m = this.findMatchingOptionInArray(currentlySelectedOptions,child.options[i].text,child.options[i].value,true);
                    if (m!=null) {
                        child.options[i].selected = true;
                        atLeastOneSelected = true;
                    }
                }
            }
            if (!atLeastOneSelected) {
                this.selectChildOptions(child,usePreselected);
            }
        }
    }
    // Change all the way down the chain
    this.change(child,usePreselected);
}
function DOL_populateChild(dolOption,childSelectObj,usePreselected) {
    // If this opton has sub-options, populate the child list with them
    if (dolOption!=null && dolOption.options!=null) {
        for (var j=0; j<dolOption.options.length; j++) {
            var srcOpt = dolOption.options[j];
            if (childSelectObj.options==null) { childSelectObj.options = new Array(); }
            // Put option into select list
            var duplicate = false;
            var preSelectedExists = false;
            for (var k=0; k<childSelectObj.options.length; k++) {
                var csi = childSelectObj.options[k];
                if (csi.text==srcOpt.text && csi.value==srcOpt.value) {
                    duplicate = true;
                    break;
                }
            }
            if (!duplicate) {
                var newopt = new Option(srcOpt.text, srcOpt.value, false, false);
                newopt.selected = false; // Again, we have to do these two statements for NN4 to work
                newopt.defaultSelected = false;
                newopt.DOLOption = srcOpt;
                childSelectObj.options[childSelectObj.options.length] = newopt;
            }
        }
    }
}

// Once a child select is populated, go back over it to select options which should be selected
function DOL_selectChildOptions(obj,usePreselected) {
    // Look to see if any options are preselected=true. If so, then set then selected if usePreselected=true, otherwise set defaults
    var values = this.values[obj.name];
    var preselectedExists = false;
    if (usePreselected && values!=null && typeof(values)!="undefined") {
        for (var i=0; i<obj.options.length; i++) {
            var v = obj.options[i].value;
            if (v!=null && values[v]!=null && typeof(values[v])!="undefined") {
                preselectedExists = true;
                break;
            }
        }
    }
    // Go back over all the options to do the selection
    var atLeastOneSelected = false;
    for (var i=0; i<obj.options.length; i++) {
        var o = obj.options[i];
        if (preselectedExists && o.value!=null && values[o.value]!=null && typeof(values[o.value])!="undefined") {
            o.selected = true;
            atLeastOneSelected = true;
        }
        else if (!preselectedExists && o.DOLOption!=null && o.DOLOption.defaultSelected) {
            o.selected = true;
            atLeastOneSelected = true;
        }
        else {
            o.selected = false;
        }
    }
    // If nothing else was selected, select the first one by default
    if (this.selectFirstOption && !atLeastOneSelected && obj.options.length>0) {
        obj.options[0].selected = true;
    }
    else if (!atLeastOneSelected &&  obj.type=="select-one") {
        obj.selectedIndex = -1;
    }
}

refreshLists();//refresh the lists when form is displayed.
-->
</script>