Author: jfthomps
Date: Fri Feb 26 20:06:42 2016
New Revision: 1732551

URL: http://svn.apache.org/viewvc?rev=1732551&view=rev
Log:
VCL-915 - Add ability for Linux images to mount NFS shares
VCL-919 - Allow customization of notification messages sent to users

siteconfig.php:
-modified generalOptions: added call to get html for NFSmounts section; added 
call to get html for messages section
-added GlobalMultiVariable class
-added NFSmounts class that inherits from GlobalMultiVariable class
-added Messages class

siteconfig.js:
-added GlobalMultiVariable class
-added nfsmount class that inherits from GlobalMultiVariable class
-instantiated nfs class
-added messages class
-instantiated messages class

utils.php:
-modified labeledFormItem: modified styling for label for textarea elements to 
vertical align the text to the top
-modified getDojoHTML: added dijit.Dialog and dojox.layout.FloatingPane to 
siteconfig mode; added import for FloatingPane.css file for stieconfig mode

code.js: modified checkValidateObj: added check for isValid method existing in 
dijit object for passed in id before calling isValid on it

vcl.css: added .highlightnotice

Modified:
    vcl/trunk/web/.ht-inc/siteconfig.php
    vcl/trunk/web/.ht-inc/utils.php
    vcl/trunk/web/css/vcl.css
    vcl/trunk/web/js/code.js
    vcl/trunk/web/js/siteconfig.js

Modified: vcl/trunk/web/.ht-inc/siteconfig.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/siteconfig.php?rev=1732551&r1=1732550&r2=1732551&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/siteconfig.php (original)
+++ vcl/trunk/web/.ht-inc/siteconfig.php Fri Feb 26 20:06:42 2016
@@ -60,6 +60,12 @@ function generalOptions($globalopts) {
 
        # -------- full width -----------
        $h .= timeSourceHTML($globalopts);
+       if($globalopts) {
+               $obj = new NFSmounts();
+               $h .= $obj->getHTML();
+       }
+       $obj = new Messages($globalopts);
+       $h .= $obj->getHTML();
        # ------ end full width ---------
 
        $h .= "<table summary=\"\" id=siteconfig>\n";
@@ -1080,4 +1086,720 @@ class NATportRange extends GlobalSingleV
        }
 }
 
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class GlobalMultiVariable
+///
+/// \brief base class for global single value variables
+///
+////////////////////////////////////////////////////////////////////////////////
+class GlobalMultiVariable {
+       var $name;
+       var $units; #array('id' => array('name' => 'razr-mgt', ...))
+       var $values; #array('id' => '<IP>:/foo/bar,/mydata')
+       var $desc;
+       var $domidbase;
+       var $basecdata;
+       var $jsname;
+       var $defaultval;
+       var $updatemsg;
+       var $type;
+       var $width;
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief class construstor
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct() {
+               $this->basecdata = array('obj' => $this);
+               $this->updatemsg = _("Values updated");
+               $type = 'text';
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getHTML()
+       ///
+       /// \return string of HTML
+       ///
+       /// \brief generates HTML for setting variables
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function getHTML() {
+               global $user;
+               $h  = "<div class=\"configwidget\" style=\"width: 100%;\">\n";
+               $h .= "<h3>{$this->name}</h3>\n";
+               $h .= "<span class=\"siteconfigdesc\">\n";
+               $h .= $this->desc;
+               $h .= "<br><br></span>\n";
+               $this->savekeys = array();
+               $this->setkeys = array();
+
+               $h .= $this->existingValuesHTML();
+
+               $unitskeys = array_keys($this->units);
+               $remainingkeys = array_diff($unitskeys, $this->setkeys);
+               $remaining = array();
+               foreach($remainingkeys as $key) {
+                       $remaining[$key] = $this->units[$key]['name'];
+               }
+               if(count($remaining) == 0)
+                       $h .= "<span id=\"{$this->domidbase}multivalnewspan\" 
class=\"hidden\">\n";
+               else
+                       $h .= "<span 
id=\"{$this->domidbase}multivalnewspan\">\n";
+
+               $h .= $this->newValueHTML($remaining);
+
+               $h .= "</span>\n"; # multivalnewspan
+
+               $h .= "<div id=\"{$this->domidbase}msg\"></div>\n";
+               $h .= dijitButton("{$this->domidbase}btn", _('Submit Changes'), 
"{$this->jsname}.saveSettings();", 1);
+               $cdata = $this->basecdata;
+               $cont = addContinuationsEntry('AJupdateAllSettings', $cdata);
+               $h .= "<input type=\"hidden\" id=\"{$this->domidbase}cont\" 
value=\"$cont\">\n";
+               $this->savekeys = implode(',', $this->savekeys);
+               $h .= "<input type=\"hidden\" id=\"{$this->domidbase}savekeys\" 
value=\"{$this->savekeys}\">\n";
+               $cont = addContinuationsEntry('AJdeleteMultiSetting', $cdata);
+               $h .= "<input type=\"hidden\" 
id=\"delete{$this->domidbase}cont\" value=\"$cont\">\n";
+               $h .= "</div>\n";
+               return $h;
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn existingValuesHTML()
+       ///
+       /// \return string of HTML
+       ///
+       /// \brief generates HTML for existing value forms
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function existingValuesHTML() {
+               $h = "<span id=\"{$this->domidbase}multivalspan\">\n";
+               foreach($this->values as $key => $val) {
+                       $this->savekeys[] = "{$this->domidbase}|$key";
+                       $this->setkeys[] = $key;
+                       $h .= "<span 
id=\"{$this->domidbase}|{$key}wrapspan\">\n";
+                       switch($this->type) {
+                               /*case 'numeric':
+                                       $extra = array('smallDelta' => 1, 
'largeDelta' => 10);
+                                       $h .= labeledFormItem($this->domidbase, 
$this->label, 'spinner', "{min:{$this->minval}, max:{$this->maxval}}", 1, $val, 
'', '', $extra);
+                                       break;
+                               case 'boolean':
+                                       $extra = array();
+                                       if($val == 1)
+                                               $extra = array('checked' => 
'checked');
+                                       $h .= labeledFormItem($this->domidbase, 
$this->label, 'check', '', 1, 1, '', '', $extra);
+                                       break;*/
+                               case 'textarea':
+                                       $h .= 
labeledFormItem("{$this->domidbase}|$key", $this->units[$key]['name'], 
'textarea', '', 1, $val, '', '', '', $this->width, '', 0);
+                                       break;
+                               default:
+                                       $h .= 
labeledFormItem("{$this->domidbase}|$key", $this->units[$key]['name'], 'text', 
"{$this->constraint}", 1, $val, "{$this->invalidmsg}", '', '', $this->width, 
'', 0);
+                                       break;
+                       }
+                       $h .= dijitButton("{$this->domidbase}|{$key}delbtn", 
_('Delete'), "{$this->jsname}.deleteMultiVal('$key', '{$this->domidbase}');") . 
"<br></span>\n";
+               }
+               $h .= "</span>\n"; # multivalspan
+               return $h;
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn newValueHTML($remaining)
+       ///
+       /// \param $remaining - array of remaining units for which values can 
be added
+       ///
+       /// \return string of HTML
+       ///
+       /// \brief generates HTML for new value form
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function newValueHTML($remaining) {
+               $h = selectInputHTML('', $remaining, 
"{$this->domidbase}newmultivalid", "dojoType=\"dijit.form.Select\"");
+
+               switch($this->type) {
+                       case 'textarea':
+                               $h .= "<textarea ";
+                               $h .=   "dojoType=\"dijit.form.Textarea\" ";
+                               $h .=   "style=\"width: {$this->width}; 
text-align: left;\" ";
+                               $h .=   "id=\"{$this->domidbase}newmultival\">";
+                               $h .= "</textarea>\n";
+                               break;
+                       default:
+                               $h .= "<input type=\"text\" ";
+                               $h .=   
"dojoType=\"dijit.form.ValidationTextBox\" ";
+                               $h .=   "regExp=\"{$this->constraint}\" ";
+                               $h .=   "invalidMessage=\"{$this->invalidmsg}\" 
";
+                               $h .=   "style=\"width: {$this->width}\" ";
+                               $h .=   "id=\"{$this->domidbase}newmultival\">";
+                               break;
+               }
+               $h .= dijitButton("{$this->domidbase}addbtn", _('Add'), 
"{$this->jsname}.addNewMultiVal();");
+               $cont = addContinuationsEntry('AJaddConfigMultiVal', 
$this->basecdata);
+               $h .= "<input type=\"hidden\" id=\"{$this->domidbase}addcont\" 
value=\"$cont\">\n";
+               return $h;
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJaddConfigMultiVal()
+       ///
+       /// \brief adds a multi value setting
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJaddConfigMultiVal() {
+               $newkey = processInputVar('multivalid', ARG_NUMERIC);
+               $newval = processInputVar('multival', ARG_STRING);
+               if(! array_key_exists($newkey, $this->units)) {
+                       $arr = array('status' => 'failed',
+                                    'msgid' => "{$this->domidbase}msg",
+                                    'btn' => "{$this->domidbase}addbtn",
+                                    'errmsg' => _("Invalid item selected for 
new value"));
+                       sendJSON($arr);
+                       return;
+               }
+               if(! $this->validateValue($newval)) {
+                       $arr = array('status' => 'failed',
+                                    'msgid' => "{$this->domidbase}msg",
+                                    'btn' => "{$this->domidbase}addbtn",
+                                    'errmsg' => _("Invalid value submitted"));
+                       if(isset($this->invalidvaluemsg))
+                               $arr['errmsg'] = $this->invalidvaluemsg;
+                       sendJSON($arr);
+                       return;
+               }
+               setVariable("{$this->domidbase}|$newkey", $newval, 'none');
+               $arr = array('status' => 'success',
+                            'msgid' => "{$this->domidbase}msg",
+                            'addid' => "{$this->domidbase}|$newkey",
+                            'addname' => $this->units[$newkey]['name'],
+                            'addval' => $newval,
+                            'delkey' => $newkey,
+                            'extrafunc' => 
"{$this->jsname}.addNewMultiValCBextra",
+                            'msg' => $this->addmsg,
+                            'regexp' => $this->constraint,
+                            'invalidmsg' => str_replace('&amp;', '&', 
$this->invalidmsg));
+               sendJSON($arr);
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJdeleteMultiSetting()
+       ///
+       /// \brief deletes a multi value setting
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJdeleteMultiSetting() {
+               $key = processInputVar('key', ARG_NUMERIC);
+               if(! array_key_exists($key, $this->values)) {
+                       $arr = array('status' => 'failed',
+                                    'msgid' => "{$this->domidbase}msg",
+                                    'btn' => "{$this->domidbase}|{$key}delbtn",
+                                    'errmsg' => _("Invalid item submitted for 
deletion"));
+                       sendJSON($arr);
+                       return;
+               }
+               deleteVariable("{$this->domidbase}|$key");
+               $arr = array('status' => 'success',
+                            'msgid' => "{$this->domidbase}msg",
+                            'delid' => "{$this->domidbase}|$key",
+                            'extrafunc' => 
"{$this->jsname}.deleteMultiValCBextra",
+                            'addid' => "$key",
+                            'addname' => $this->units[$key]['name'],
+                            'msg' => $this->delmsg);
+               sendJSON($arr);
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJupdateAllSettings()
+       ///
+       /// \brief updates all values for implemented type of timevariable
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJupdateAllSettings() {
+               if(! checkUserHasPerm('Site Configuration (global)')) {
+                       $arr = array('status' => 'noaccess',
+                                    'msg' => _('You do not have access to 
modify the submitted settings.'));
+                       sendJSON($arr);
+                       return;
+               }
+               $origvals = $this->values;
+               $newvals = array();
+               foreach($origvals as $key => $val) {
+                       switch($this->type) {
+                               /*case 'numeric':
+                                       $newval = processInputVar('newval', 
ARG_NUMERIC); 
+                                       if($newval < $this->minval || $newval > 
$this->maxval) {
+                                               $arr = array('status' => 
'failed',
+                                                            'msgid' => 
"{$this->domidbase}msg",
+                                                            'btn' => 
"{$this->domidbase}btn",
+                                                            'errmsg' => 
_("Invalid value submitted"));
+                                               sendJSON($arr);
+                                               return;
+                                       }
+                                       break;
+                               case 'boolean':
+                                       $newval = processInputVar('newval', 
ARG_NUMERIC); 
+                                       if($newval !== '0' && $newval !== '1') {
+                                               $arr = array('status' => 
'failed',
+                                                            'msgid' => 
"{$this->domidbase}msg",
+                                                            'btn' => 
"{$this->domidbase}btn",
+                                                            'errmsg' => 
_("Invalid value submitted"));
+                                               sendJSON($arr);
+                                               return;
+                                       }
+                                       break;*/
+                               case 'text':
+                               case 'textarea':
+                                       $newval = 
processInputVar("{$this->domidbase}|$key", ARG_STRING); 
+                                       if(! $this->validateValue($newval)) {
+                                               $arr = array('status' => 
'failed',
+                                                            'msgid' => 
"{$this->domidbase}msg",
+                                                            'btn' => 
"{$this->domidbase}btn",
+                                                            'errmsg' => 
_("Invalid value submitted for ") . $this->units[$key]['name']);
+                                               sendJSON($arr);
+                                               return;
+                                       }
+                                       if($newval != $origvals[$key])
+                                               
$newvals["{$this->jsname}|$key"] = $newval;
+                                       break;
+                               /*case 'textarea':
+                                       $newval = processInputVar('newval', 
ARG_STRING); 
+                                       if(! $this->validateValue($newval)) {
+                                               $arr = array('status' => 
'failed',
+                                                            'msgid' => 
"{$this->domidbase}msg",
+                                                            'btn' => 
"{$this->domidbase}btn",
+                                                            'errmsg' => 
_("Invalid value submitted"));
+                                               
if(isset($this->invalidvaluemsg))
+                                                       $arr['errmsg'] = 
$this->invalidvaluemsg;
+                                               sendJSON($arr);
+                                               return;
+                                       }
+                                       break;*/
+                               default:
+                                       $arr = array('status' => 'failed',
+                                                    'msgid' => 
"{$this->domidbase}msg",
+                                                    'btn' => 
"{$this->domidbase}btn",
+                                                    'errmsg' => _("Invalid 
value submitted"));
+                                       sendJSON($arr);
+                                       return;
+                       }
+               }
+               foreach($newvals as $key => $val)
+                       setVariable($key, $val, 'none');
+               $arr = array('status' => 'success',
+                            'msgid' => "{$this->domidbase}msg",
+                            'btn' => "{$this->domidbase}btn",
+                            'msg' => $this->updatemsg);
+               sendJSON($arr);
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn validateValue($val)
+       ///
+       /// \brief validates that a new value is okay; should be implemented in 
+       /// inheriting class
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function validateValue($val) {
+               return 1;
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class NFSmounts
+///
+/// \brief extends GlobalMultiVariable class to implement NFSmounts
+///
+////////////////////////////////////////////////////////////////////////////////
+class NFSmounts extends GlobalMultiVariable {
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief class construstor
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct() {
+               parent::__construct();
+               $this->name = _('NFS Mounts');
+               $this->units = getManagementNodes();
+               foreach($this->units as $key => $val) {
+                       $this->units[$key]['name'] = $val['hostname'];
+               }
+               $vals = getVariablesRegex('^nfsmount\\\|[0-9]+$');
+               $this->values = array();
+               foreach($vals as $key => $val) {
+                       $tmp = explode('|', $key);
+                       $id = $tmp[1];
+                       $this->values[$id] = $val;
+               }
+               $formbase = ' &lt;hostname or IP&gt;:&lt;export 
path&gt;,&lt;mount path&gt;';
+               $this->desc = _("NFS Mounts are NFS exports that are to be 
mounted within each reservation deployed by a given management node.<br>Values 
must be like") . $formbase;
+               $this->domidbase = 'nfsmount';
+               $this->basecdata['obj'] = $this;
+               $this->jsname = 'nfsmount';
+               $this->defaultval = '';
+               $this->type = 'textarea';
+               $this->addmsg = "NFS mount sucessfully added";
+               $this->delmsg = "NFS mount sucessfully deleted";
+               $this->constraint = 
'((((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|([A-Za-z0-9\-\.]+)):\/[a-zA-Z0-9\.@#%\(\)-_=\+\/]+,\/[a-zA-Z0-9\.@#%\(\)-_=\+\/]+';
+               $this->invalidmsg = _("Invalid value - must be in the form") . 
str_replace('&', '&amp;', $formbase);
+               $this->invalidvaluemsg = html_entity_decode($this->invalidmsg);
+               $this->width = '400px';
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn validateValue($val)
+       ///
+       /// \brief validates that a new value is okay
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function validateValue($val) {
+               $vals = explode(";", $val);
+               foreach($vals as $testval) {
+                       $tmp = explode(':', $testval);
+                       if(count($tmp) != 2)
+                               return 0;
+                       $iphost = $tmp[0];
+                       if(preg_match('/^[0-9\.]+$/', $iphost) && ! 
validateIPv4addr($iphost))
+                               return 0;
+                       elseif(! preg_match('/^[A-Za-z0-9\-\.]+$/', $iphost))
+                               return 0;
+                       $tmp = explode(',', $tmp[1]);
+                       if(count($tmp) != 2)
+                               return 0;
+                       $exportpath = $tmp[0];
+                       $mntpath = $tmp[1];
+                       if(! preg_match(':^/[a-zA-Z0-9\.@#%\(\)-_=\+/]+:', 
$exportpath))
+                               return 0;
+                       if(! preg_match(':^/[a-zA-Z0-9\.@#%\(\)-_=\+/]+:', 
$mntpath))
+                               return 0;
+               }
+               return 1;
+       }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+///
+/// \class Messages
+///
+/// \brief class to handle configuration of Messages
+///
+////////////////////////////////////////////////////////////////////////////////
+class Messages {
+       var $basecdata;
+       var $name;
+       var $desc;
+       var $affils;
+       var $units;
+       var $basekeys;
+       var $globalopts;
+
+       
/////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn __construct()
+       ///
+       /// \brief class construstor
+       ///
+       
/////////////////////////////////////////////////////////////////////////////
+       function __construct($globalopts) {
+               $this->basecdata['obj'] = $this;
+               $this->name = _('Messages');
+               $this->desc = sprintf(_("This section allows for configuration 
of messages that are sent to users and administrators about things such as 
reservations and image management. Every message has a default. Additionally, 
separate messages can be configured for each affiliation. Most of the messages 
will have parts that are in square brackets. These parts will have data 
substituted for them before the message is sent. A list of what can be used in 
squeare brackets can be found at the <a href=\"%s\">Apache VCL web site</a>. 
Some messages also have a short form that may be sent such as in the form of a 
popup within a reservation when the reservation is about to end."), 
"http://vcl.apache.org/docs/message_substitutions.html";);
+               $this->affils = getAffiliations();
+               $this->units = array();
+               $this->basekeys = array();
+               $this->globalopts = $globalopts;
+
+               if($this->globalopts)
+                       $data = 
getVariablesRegex('^(usermessage\\\||adminmessage\\\|)');
+               else
+                       $data = getVariablesRegex('^usermessage\\\|');
+               foreach($data as $key => $item) {
+                       # 0 - category, 1 - type, 2 - affil
+                       $keyparts = explode('|', $key);
+                       $k = "{$keyparts[0]}|{$keyparts[1]}";
+                       $kname = "{$keyparts[0]} -&gt; {$keyparts[1]}";
+                       $this->basekeys[$k] = $kname;
+
+                       if($keyparts[0] == 'adminmessage')
+                               $keyparts[2] = 'Global';
+                       $this->units[$k][$keyparts[2]] = $item;
+               }
+               uasort($this->basekeys, "sortKeepIndex");
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn getHTML()
+       ///
+       /// \return string of HTML
+       ///
+       /// \brief generates HTML for setting variables
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function getHTML() {
+               global $user;
+               $h  = "<div class=\"configwidget\" style=\"width: 100%;\">\n";
+               $h .= "<h3>{$this->name}</h3>\n";
+               $h .= "<div style=\"text-align: left; padding: 4px;\">\n";
+               $h .= $this->desc;
+               $h .= "<br><br></div>\n";
+
+               $h .= "<script type=\"application/json\" 
id=\"messagesdata\">\n";
+               $h .= json_encode($this->units); 
+               $h .= "</script>\n";
+
+               $h .= "<strong>Select Message</strong>:";
+               $extra = "dojoType=\"dijit.form.FilteringSelect\" "
+                      . "style=\"width: 300px\" "
+                      . "onChange=\"messages.setContents(1);\"";
+               $h .= selectInputHTML('', $this->basekeys, "messagesselid", 
$extra);
+               $h .= "<br>\n";
+               if($this->globalopts) {
+                       $h .= "<strong>Select Affiliation</strong>:";
+                       $h .= selectInputHTML('', $this->affils, 
"messagesaffilid", $extra);
+               }
+               else {
+                       $opts = array($user['affiliationid'] => 
$this->affils[$user['affiliationid']]);
+                       $h .= "<strong>Affiliation: 
{$this->affils[$user['affiliationid']]}</strong>";
+                       $h .= "<div class=\"hidden\">\n";
+                       $h .= selectInputHTML('', $opts, "messagesaffilid", 
$extra);
+                       $h .= "</div>\n";
+               }
+
+               $h .= "<br>\n";
+               $h .= "<div id=\"defaultmessagesdiv\" class=\"hidden 
highlightnotice\"><br><strong>";
+               $h .= i('There is no message set specifically for this 
affiliation. The default message is being used and is displayed below.');
+               $h .= "</strong><br><br></div>\n";
+               $h .= labeledFormItem("messagessubject", 'Subject', 'text', '', 
1, '', '', '', '', '80ch');
+               $h .= labeledFormItem("messagesbody", 'Message', 'textarea', 
'', 1, '', '', '', '', '80ch');
+               $h .= labeledFormItem("messagesshortmsg", 'Short Message', 
'textarea', '', 1, '', '', '', '', '80ch');
+
+               $h .= "<span id=\"messagesaffil\" style=\"font-weight: bold;\"";
+               if(! $this->globalopts)
+                       $h .= " class=\"hidden\"";
+               $h .= ">Default message for any affiliation</span><br>\n";
+
+               $h .= dijitButton("messagessavebtn", _('Save Message'), 
"messages.savemsg();");
+               $h .= dijitButton("messagesdelbtn", _('Delete Message and Use 
Default'), "messages.confirmdeletemsg();");
+
+               $h .= "<div dojoType=dijit.Dialog\n";
+               $h .= "      id=\"deleteMessageDlg\"\n";
+               $h .= "      title=\"" . i("Delete Message") . "\"\n";
+               $h .= "      duration=250\n";
+               $h .= "      draggable=true\n";
+               $h .= "      style=\"width: 315px;\">\n";
+               $h .= "Are you sure you want to delete the selected message for 
this affiliaton ";
+               $h .= "and use the default message instead?<br><br>\n";
+               $h .= "<span style=\"font-weight: bold\">Affiliation:</span> 
<span id=\"deleteMsgAffil\"></span><br>\n";
+               $h .= "<span style=\"font-weight: bold\">Category:</span> <span 
id=\"deleteMsgCategory\"></span><br>\n";
+               $h .= "<span style=\"font-weight: bold\">Type:</span> <span 
id=\"deleteMsgType\"></span><br><br>\n";
+               $h .= "   <div align=\"center\">\n";
+               $h .= "   <button id=\"deleteMessageDelBtn\" 
dojoType=\"dijit.form.Button\">\n";
+               $h .= "    " . i("Delete Message") . "\n";
+               $h .= "     <script type=\"dojo/method\" event=\"onClick\">\n";
+               $h .= "       messages.deletemsg();\n";
+               $h .= "     </script>\n";
+               $h .= "   </button>\n";
+               $h .= "   <button dojoType=\"dijit.form.Button\">\n";
+               $h .= "     " . i("Cancel") . "\n";
+               $h .= "     <script type=\"dojo/method\" event=\"onClick\">\n";
+               $h .= "       dijit.byId('deleteMessageDlg').hide();\n";
+               $h .= "     </script>\n";
+               $h .= "   </button>\n";
+               $h .= "   </div>\n";
+               $h .= "</div>\n";
+
+               $h .= "<div dojoType=dojox.layout.FloatingPane\n";
+               $h .= "      id=\"invalidmsgfieldspane\"\n";
+               $h .= "      resizable=\"true\"\n";
+               $h .= "      closable=\"true\"\n";
+               $h .= "      title=\"" . i("Invalid Message Fields") . "\"\n";
+               $h .= "      style=\"width: 400px; ";
+               $h .=               "height: 200px; ";
+               $h .=               "visibility: hidden; ";
+               $h .=               "text-align: left; ";
+               $h .=               "border: solid 2px red;\"\n";
+               $h .= ">\n";
+               $h .= "<script type=\"dojo/method\" event=\"minimize\">\n";
+               $h .= "  this.hide();\n";
+               $h .= "</script>\n";
+               $h .= "<script type=\"dojo/method\" event=\"close\">\n";
+               $h .= "  this.hide();\n";
+               $h .= "  return false;\n";
+               $h .= "</script>\n";
+               $h .= "<div style=\"padding: 4px;\">\n";
+               $h .= _("The following messages have invalid items included for 
substitution. Please correct the message contents and save them again for the 
backend to validate.") . "<br><br>\n";
+               $h .= "   <div id=\"invalidmsgfieldcontent\"></div>\n";
+               $h .= "</div>\n";
+               $h .= "</div>\n";
+
+               $cdata = $this->basecdata;
+               $h .= "<div id=\"messagesmsg\"></div>\n";
+               $cont = addContinuationsEntry('AJsaveMessages', $cdata);
+               $h .= "<input type=\"hidden\" id=\"savemessagescont\" 
value=\"$cont\">\n";
+               $cont = addContinuationsEntry('AJdeleteMessages', $cdata);
+               $h .= "<input type=\"hidden\" id=\"deletemessagescont\" 
value=\"$cont\">\n";
+
+               $cont = addContinuationsEntry('AJvalidateMessagesPoll', $cdata);
+               $h .= "<input type=\"hidden\" id=\"validatemessagespollcont\" 
value=\"$cont\">\n";
+
+               $h .= "</div>\n";
+
+               return $h;
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJdeleteMessages()
+       ///
+       /// \brief deletes an affiliation specific message
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJdeleteMessages() {
+               global $user;
+               $key = processInputVar('key', ARG_STRING);
+               $affilid = processInputVar('affilid', ARG_NUMERIC);
+               $keyparts = explode('|', $key);
+               if(! array_key_exists($key, $this->basekeys) ||
+                  ! array_key_exists($affilid, $this->affils) ||
+                  count($keyparts) != 2 ||
+                  $this->affils[$affilid] == 'Global' ||
+                  ($this->globalopts == 0 && $affilid != 
$user['affiliationid'])) {
+                       $arr = array('status' => 'failed',
+                                    'msgid' => "messagesmsg",
+                                    'btn' => "messagesdelbtn",
+                                    'errmsg' => _("Invalid item submitted for 
deletion"));
+                       sendJSON($arr);
+                       return;
+               }
+               $affil = $this->affils[$affilid];
+               $delkey = "$key|$affil";
+               deleteVariable($delkey);
+               $arr = array('status' => 'success',
+                            'msgid' => "messagesmsg",
+                            'key' => $key,
+                            'affil' => $affil,
+                            'extrafunc' => "messages.deleteMessagesCBextra",
+                            'btn' => "messagesdelbtn",
+                            'msg' => sprintf(_('Message type %s for 
affiliation %s successfully deleted'), $keyparts[1], $affil));
+               sendJSON($arr);
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJsaveMessages()
+       ///
+       /// \brief saves an affiliation specific message
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJsaveMessages() {
+               global $user;
+               $key = processInputVar('key', ARG_STRING);
+               $affilid = processInputVar('affilid', ARG_NUMERIC);
+               $subject = processInputVar('subject', ARG_STRING);
+               $body = processInputVar('body', ARG_STRING);
+               $shortmsg = processInputVar('shortmsg', ARG_STRING);
+
+               $keyparts = explode('|', $key);
+
+               if(! array_key_exists($key, $this->basekeys) ||
+                  ! array_key_exists($affilid, $this->affils) ||
+                       count($keyparts) != 2 ||
+                  ($this->globalopts == 0 && $keyparts[0] == 'adminmessage') ||
+                  ($this->globalopts == 0 && $affilid != 
$user['affiliationid'])) {
+                       $arr = array('status' => 'failed',
+                                    'msgid' => "messagesmsg",
+                                    'btn' => "messagessavebtn",
+                                    'errmsg' => _("Invalid item submitted to 
save"));
+                       sendJSON($arr);
+                       return;
+               }
+               $affil = $this->affils[$affilid];
+               $savekey = $key;
+               if($keyparts[0] == 'usermessage')
+                       $savekey = "{$keyparts[0]}|{$keyparts[1]}|$affil";
+               $data = getVariable($savekey);
+               if(is_null($data))
+                       $data = array();
+               $changed = 0;
+               if(! array_key_exists('subject', $data) || $data['subject'] != 
$subject) {
+                       $data['subject'] = $subject;
+                       $changed = 1;
+               }
+               if(! array_key_exists('message', $data) || $data['message'] != 
$body) {
+                       $data['message'] = $body;
+                       $changed = 1;
+               }
+               if($keyparts[0] == 'usermessage' &&
+                       (! array_key_exists('usermessage', $data) ||
+                       $data['short_message'] != $shortmsg)) {
+                       $data['short_message'] = $shortmsg;
+                       $changed = 1;
+               }
+               if($changed) {
+                       if(preg_match('/\[.*\]/', $body) ||
+                          preg_match('/\[.*\]/', $shortmsg))
+                               setVariable('usermessage_needs_validating', 1, 
'none');
+                       unset($data['invalidfields']);
+                       setVariable($savekey, $data, 'yaml');
+                       $usermsg = _('Message successfully saved');
+               }
+               else
+                       $usermsg = _('No changes to submitted message. Nothing 
saved.');
+               $arr = array('status' => 'success',
+                            'msgid' => "messagesmsg",
+                            'key' => $key,
+                            'affil' => $affil,
+                            'subject' => $subject,
+                            'body' => $body,
+                            'shortmsg' => $shortmsg,
+                            'extrafunc' => "messages.saveMessagesCBextra",
+                            'btn' => "messagessavebtn",
+                            'msg' => $usermsg);
+               sendJSON($arr);
+       }
+
+       
////////////////////////////////////////////////////////////////////////////////
+       ///
+       /// \fn AJvalidateMessagesPoll()
+       ///
+       /// \brief checks for errors found by vcld in any recently updated 
messages
+       ///
+       
////////////////////////////////////////////////////////////////////////////////
+       function AJvalidateMessagesPoll() {
+               $query = "SELECT v1.name, "
+                      .        "v1.value "
+                      . "FROM variable v1, "
+                      .      "variable v2 "
+                      . "WHERE v1.setby != 'webcode' AND "
+                      .       "v1.setby IS NOT NULL AND "
+                      .       "v2.name = 'usermessage_needs_validating' AND "
+                      .       "v1.timestamp > DATE_SUB(v2.timestamp, INTERVAL 
5 MINUTE)";
+               $qh = doQuery($query);
+               $invalids = array();
+               while($row = mysql_fetch_assoc($qh)) {
+                       $data = Spyc::YAMLLoad($row['value']);
+                       if(array_key_exists('invalidfields', $data)) {
+                               $invalids[$row['name']] = 
$data['invalidfields'];
+                       }
+               }
+               if(count($invalids)) {
+                       sendJSON(array('status' => 'invalid', 'values' => 
$invalids));
+                       return;
+               }
+               sendJSON(array('status' => 'valid'));
+       }
+}
+
 ?>

Modified: vcl/trunk/web/.ht-inc/utils.php
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/.ht-inc/utils.php?rev=1732551&r1=1732550&r2=1732551&view=diff
==============================================================================
--- vcl/trunk/web/.ht-inc/utils.php (original)
+++ vcl/trunk/web/.ht-inc/utils.php Fri Feb 26 20:06:42 2016
@@ -9110,7 +9110,7 @@ function labeledFormItem($id, $label, $t
                case 'textarea':
                        if($width == '')
                                $width = '300px';
-                       $h .= "<label for=\"$id\">$label:</label>\n";
+                       $h .= "<label style=\"vertical-align: top;\" 
for=\"$id\">$label:</label>\n";
                        $h .= "<span class=\"labeledform\">\n";
                        $h .= "<textarea ";
                        $h .=        "dojoType=\"dijit.form.Textarea\" ";
@@ -12962,6 +12962,7 @@ function getDojoHTML($refresh) {
                case 'siteconfig':
                        $filename = 'siteconfig.js';
                        $dojoRequires = array('dojo.parser',
+                                             'dijit.Dialog',
                                              'dijit.form.Button',
                                              'dijit.form.Textarea',
                                              'dijit.form.FilteringSelect',
@@ -12970,6 +12971,7 @@ function getDojoHTML($refresh) {
                                              'dijit.form.CheckBox',
                                              'dijit.form.ValidationTextBox',
                                              'dijit.layout.ContentPane',
+                                             'dojox.layout.FloatingPane',
                                              'dijit.layout.TabContainer');
                        break;
                # TODO clean up
@@ -13366,6 +13368,7 @@ function getDojoHTML($refresh) {
                case "siteconfig":
                        $rt .= "<style type=\"text/css\">\n";
                        $rt .= "   @import 
\"themes/$skin/css/dojo/$skin.css\";\n";
+                       $rt .= "   @import 
\"dojo/dojox/layout/resources/FloatingPane.css\";\n";
                        $rt .= "   @import \"css/siteconfig.css\";\n";
                        $rt .= "</style>\n";
                        $rt .= "<script type=\"text/javascript\" 
src=\"js/siteconfig.js?v=$v\"></script>\n";

Modified: vcl/trunk/web/css/vcl.css
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/css/vcl.css?rev=1732551&r1=1732550&r2=1732551&view=diff
==============================================================================
--- vcl/trunk/web/css/vcl.css (original)
+++ vcl/trunk/web/css/vcl.css Fri Feb 26 20:06:42 2016
@@ -305,6 +305,13 @@ body {
        text-align: left;
 }
 
+.highlightnotice {
+       background-color: #fffa9a;
+       border: 2px solid #eaea00;
+       padding: 3px;
+       margin: 10px;
+}
+
 .highlightnoticewarn {
        background-color: #ffcccc;
        border: 2px solid #ff0000;

Modified: vcl/trunk/web/js/code.js
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/js/code.js?rev=1732551&r1=1732550&r2=1732551&view=diff
==============================================================================
--- vcl/trunk/web/js/code.js (original)
+++ vcl/trunk/web/js/code.js Fri Feb 26 20:06:42 2016
@@ -346,7 +346,7 @@ function resizeRecenterDijitDialog(id) {
 
 function checkValidatedObj(objid, errobj) {
        if(dijit.byId(objid) && ! dijit.byId(objid).get('disabled') &&
-          ! dijit.byId(objid).isValid()) {
+          'isValid' in dijit.byId(objid) && ! dijit.byId(objid).isValid()) {
                dijit.byId(objid)._hasBeenBlurred = true;
                dijit.byId(objid).validate();
                //dijit.byId(objid).focus();

Modified: vcl/trunk/web/js/siteconfig.js
URL: 
http://svn.apache.org/viewvc/vcl/trunk/web/js/siteconfig.js?rev=1732551&r1=1732550&r2=1732551&view=diff
==============================================================================
--- vcl/trunk/web/js/siteconfig.js (original)
+++ vcl/trunk/web/js/siteconfig.js Fri Feb 26 20:06:42 2016
@@ -249,3 +249,339 @@ function natPortRange() {
 }
 natPortRange.prototype = new GlobalSingleVariable();
 var natPortRange = new natPortRange();
+
+function GlobalMultiVariable() {}
+GlobalMultiVariable.prototype.saveSettings = function() {
+       var data = {continuation: dojo.byId(this.domidbase + 'cont').value};
+
+       var keys = dojo.byId(this.domidbase + 'savekeys').value.split(',');
+       for(var i = 0; i < keys.length; i++) {
+               if('checked' in dijit.byId(keys[i])) {
+                       if(dijit.byId(keys[i]).checked)
+                               data[keys[i]] = dijit.byId(keys[i]).value;
+                       else
+                               data[keys[i]] = 0;
+               }
+               else {
+                       if(! checkValidatedObj(keys[i])) {
+                               dijit.byId(keys[i]).focus();
+                               return;
+                       }
+                       data[keys[i]] = dijit.byId(keys[i]).get('value');
+               }
+       }
+       dijit.byId(this.domidbase + 'btn').set('disabled', true);
+       RPCwrapper(data, generalSiteConfigCB, 1);
+}
+GlobalMultiVariable.prototype.addNewMultiVal = function() {
+       var data = {continuation: dojo.byId(this.domidbase + 'addcont').value,
+                   multivalid: dijit.byId(this.domidbase + 
'newmultivalid').get('value'),
+                   multival: dijit.byId(this.domidbase + 
'newmultival').get('value')};
+       dijit.byId(this.domidbase + 'addbtn').set('disabled', true);
+       RPCwrapper(data, generalSiteConfigCB, 1);
+}
+GlobalMultiVariable.prototype.addNewMultiValCBextra = function(data) {
+       var span = document.createElement('span');
+       span.setAttribute('id', data.items.addid + 'wrapspan');
+       var label = document.createElement('label');
+       label.setAttribute('for', data.items.addid);
+       label.innerHTML = data.items.addname + ': ';
+       span.appendChild(label);
+       var span2 = document.createElement('span');
+       span2.setAttribute('class', 'labeledform');
+       var text = new dijit.form.ValidationTextBox({
+               id: data.items.addid,
+               required: 'true',
+               style: 'width: 400px;',
+               value: data.items.addval,
+               regExp: data.items.regexp,
+               invalidMessage: data.items.invalidmsg
+       }, document.createElement('div'));
+       span2.appendChild(text.domNode);
+       span.appendChild(span2);
+       var func = this.deleteMultiVal
+       var domidbase = this.domidbase;
+       var btn = new dijit.form.Button({
+               id: data.items.addid + 'delbtn',
+               label: _('Delete'),
+               onClick: function() {
+                       func(data.items.delkey, domidbase);
+               }
+       }, document.createElement('div'));
+       span.appendChild(btn.domNode);
+       span.appendChild(document.createElement('br'));
+       dojo.byId(this.domidbase + 'multivalspan').appendChild(span);
+       dijit.byId(this.domidbase + 'newmultival').set('value', '');
+       dijit.byId(this.domidbase + 'newmultivalid').removeOption({value: 
data.items.delkey});
+       if(dijit.byId(this.domidbase + 'newmultivalid').options.length == 0)
+               dojo.addClass(this.domidbase + 'multivalnewspan', 'hidden');
+       var keys = dojo.byId(this.domidbase + 'savekeys').value.split(',');
+       keys.push(data.items.addid);
+       dojo.byId(this.domidbase + 'savekeys').value = keys.join(',');
+       dijit.byId(this.domidbase + 'addbtn').set('disabled', false);
+}
+GlobalMultiVariable.prototype.deleteMultiVal = function(key, domidbase) {
+       var data = {key: key,
+                   continuation: dojo.byId('delete' + domidbase + 
'cont').value};
+       RPCwrapper(data, generalSiteConfigCB, 1);
+}
+GlobalMultiVariable.prototype.deleteMultiValCBextra = function(data) {
+       dijit.byId(data.items.delid).destroy();
+       dijit.byId(data.items.delid + 'delbtn').destroy();
+       dojo.destroy(data.items.delid + 'wrapspan');
+       dijit.byId(this.domidbase + 'newmultivalid').addOption({value: 
data.items.addid, label: data.items.addname});
+       //dojo.removeClass(this.domidbase + 'adddiv', 'hidden');
+       var keys = dojo.byId(this.domidbase + 'savekeys').value.split(',');
+       var newkeys = new Array();
+       for(var i = 0; i < keys.length; i++) {
+               if(keys[i] != data.items.delid)
+                       newkeys.push(keys[i]);
+       }
+       dojo.byId(this.domidbase + 'savekeys').value = newkeys.join(',');
+       //dojo.byId(this.domidbase + 'cont').value = data.items.savecont;
+       dojo.removeClass(this.domidbase + 'multivalnewspan', 'hidden');
+}
+
+function nfsmount() {
+       GlobalMultiVariable.apply(this, Array.prototype.slice.call(arguments));
+       this.domidbase = 'nfsmount';
+}
+nfsmount.prototype = new GlobalMultiVariable();
+var nfsmount = new nfsmount();
+
+function messages() {
+       var items;
+       var timer;
+       var validatecnt;
+       var invalids;
+       this.init();
+}
+messages.prototype.init = function() {
+       if(typeof dijit !== 'object' || dijit.byId('messagesselid') === 
undefined) {
+               setTimeout(this.init, 500);
+               return;
+       }
+       messages.setContents(1);
+       messages.invalids = new Object();
+       setTimeout(function() {
+               messages.validatecnt = 1;
+               messages.validatePoll();
+       }, 1000);
+}
+messages.prototype.validateContent = function() {
+       var subj = dijit.byId('messagessubject').get('value');
+       if(! this.checkBalancedBrackets(subj)) {
+               dojo.addClass('messagesmsg', 'cfgerror');
+               dojo.removeClass('messagesmsg', 'cfgsuccess');
+               dojo.byId('messagesmsg').innerHTML = _('Unmatched or empty 
brackets ( [ and ] ) in subject');
+               return false;
+       }
+       var body = dijit.byId('messagesbody').get('value');
+       if(! this.checkBalancedBrackets(body)) {
+               dojo.addClass('messagesmsg', 'cfgerror');
+               dojo.removeClass('messagesmsg', 'cfgsuccess');
+               dojo.byId('messagesmsg').innerHTML = _('Unmatched or empty 
brackets ( [ and ] ) in message');
+               return false;
+       }
+       var shortmsg = dijit.byId('messagesshortmsg').get('value');
+       if(! this.checkBalancedBrackets(shortmsg)) {
+               dojo.addClass('messagesmsg', 'cfgerror');
+               dojo.removeClass('messagesmsg', 'cfgsuccess');
+               dojo.byId('messagesmsg').innerHTML = _('Unmatched or empty 
brackets ( [ and ] ) in short message');
+               return false;
+       }
+       return true;
+}
+messages.prototype.checkBalancedBrackets = function(string) {
+       var len = string.length;
+       var inBracket = 0;
+       var hasContent = 0;
+       for(var i = 0; i < len; i++) {
+               var ch = string.charAt(i);
+               switch(ch) {
+                       case '[':
+                               if(inBracket)
+                                       return false;
+                               inBracket = 1;
+                               hasContent = 0;
+                               break;
+                       case ']':
+                               if(! hasContent)
+                                       return false;
+                               inBracket = 0;
+                               hasContent = 0;
+                               break;
+                       default:
+                               if(inBracket)
+                                       hasContent = 1;
+               }
+       }
+       if(inBracket)
+               return false;
+       return true;
+}
+messages.prototype.setContents = function(clearmsg) {
+       if(messages.items === undefined) {
+               messages.items = 
JSON.parse(document.getElementById('messagesdata').innerHTML);
+       }
+       var msgkey = dijit.byId('messagesselid').get('value');
+       var msgkeyparts = msgkey.split('|');
+       if(msgkeyparts[0] == 'adminmessage') {
+               dijit.byId('messagesaffilid').set('displayedValue', 'Global');
+               dijit.byId('messagesaffilid').set('disabled', true);
+       }
+       else {
+               dijit.byId('messagesaffilid').set('disabled', false);
+       }
+       var affil = dijit.byId('messagesaffilid').get('displayedValue');
+       var key = msgkey + '|' + affil;
+       if(affil == 'Global' || ! (affil in messages.items[msgkey])) {
+               // use default
+               dijit.byId('messagesdelbtn').set('disabled', true);
+               var item = messages.items[msgkey]['Global'];
+               if(affil == 'Global') {
+                       dojo.addClass('defaultmessagesdiv', 'hidden');
+               }
+               else {
+                       dojo.removeClass('defaultmessagesdiv', 'hidden');
+               }
+       }
+       else {
+               // use affil specific msg
+               dijit.byId('messagesdelbtn').set('disabled', false);
+               var item = messages.items[msgkey][affil];
+               dojo.addClass('defaultmessagesdiv', 'hidden');
+       }
+       var affiltype;
+       if(affil == 'Global') {
+               affiltype = 'Default message for any affiliation';
+       }
+       else {
+               affiltype = 'Message for ' + affil + ' affiliation';
+       }
+       dojo.byId('messagesaffil').innerHTML = affiltype;
+       dijit.byId('messagessubject').set('value', item['subject']);
+       dijit.byId('messagesbody').set('value', item['message']);
+       if('short_message' in item)
+               dijit.byId('messagesshortmsg').set('value', 
item['short_message']);
+       else
+               dijit.byId('messagesshortmsg').set('value', '');
+       if(clearmsg) {
+               dojo.removeClass('messagesmsg', 'cfgerror');
+               dojo.removeClass('messagesmsg', 'cfgsuccess');
+               dojo.byId('messagesmsg').innerHTML = '';
+       }
+}
+messages.prototype.confirmdeletemsg = function() {
+       var affil = dijit.byId('messagesaffilid').get('displayedValue');
+       if(affil == 'Global')
+               return;
+       var key = dijit.byId('messagesselid').get('value');
+       var keyparts = key.split('|');
+       dojo.byId('deleteMsgAffil').innerHTML = affil;
+       dojo.byId('deleteMsgCategory').innerHTML = keyparts[0];
+       dojo.byId('deleteMsgType').innerHTML = keyparts[1];
+       dijit.byId('deleteMessageDlg').show();
+}
+messages.prototype.deletemsg = function() {
+       dijit.byId('messagesdelbtn').set('disabled', true);
+       dijit.byId('messagesselid').set('disabled', true);
+       dijit.byId('messagesaffilid').set('disabled', true);
+       var data = {key: dijit.byId('messagesselid').get('value'),
+                   affilid: dijit.byId('messagesaffilid').get('value'),
+                   continuation: dojo.byId('deletemessagescont').value};
+       RPCwrapper(data, generalSiteConfigCB, 1);
+}
+messages.prototype.deleteMessagesCBextra = function(data) {
+       dijit.byId('messagesselid').set('disabled', false);
+       dijit.byId('messagesaffilid').set('disabled', false);
+       delete messages.items[data.items.key][data.items.affil];
+       dijit.byId('deleteMessageDlg').hide();
+       messages.setContents(0);
+}
+messages.prototype.savemsg = function() {
+       if(! this.validateContent()) {
+               return;
+       }
+       var invalidkey = dijit.byId('messagesselid').get('value') + '|' + 
dijit.byId('messagesaffilid').get('displayedValue');
+       if('invalidkey' in this.invalids) {
+               this.invalids.splice(invalidkey, 1);
+               this.updateInvalidContent();
+       }
+       dijit.byId('messagessavebtn').set('disabled', true);
+       dijit.byId('messagesselid').set('disabled', true);
+       dijit.byId('messagesaffilid').set('disabled', true);
+       var data = {key: dijit.byId('messagesselid').get('value'),
+                   affilid: dijit.byId('messagesaffilid').get('value'), 
+                   subject: dijit.byId('messagessubject').get('value'), 
+                   body:  dijit.byId('messagesbody').get('value'),
+                   shortmsg:  dijit.byId('messagesshortmsg').get('value'),
+                   continuation: dojo.byId('savemessagescont').value};
+       RPCwrapper(data, generalSiteConfigCB, 1);
+}
+messages.prototype.saveMessagesCBextra = function(data) {
+       dijit.byId('messagesselid').set('disabled', false);
+       dijit.byId('messagesaffilid').set('disabled', false);
+       messages.items[data.items.key][data.items.affil] = new Object();
+       messages.items[data.items.key][data.items.affil]['name'] = 
data.items.name;
+       messages.items[data.items.key][data.items.affil]['subject'] = 
data.items.subject;
+       messages.items[data.items.key][data.items.affil]['message'] = 
data.items.body;
+       messages.items[data.items.key][data.items.affil]['short_message'] = 
data.items.shortmsg;
+       dijit.byId('deleteMessageDlg').hide();
+       messages.setContents(0);
+       messages.startValidatePoll();
+}
+messages.prototype.validatePoll = function() {
+       var data = {continuation: dojo.byId('validatemessagespollcont').value};
+       RPCwrapper(data, this.validatePollCB, 1);
+       this.validatecnt--;
+}
+messages.prototype.validatePollCB = function(data, ioArgs) {
+       if(data.items.status == 'invalid') {
+               messages.invalids = data.items.values;
+               messages.updateInvalidContent();
+       }
+       else {
+               messages.invalids = new Object();
+               dijit.byId('invalidmsgfieldspane').hide();
+       }
+       clearTimeout(this.timer);
+       if(messages.validatecnt <= 0)
+               return;
+       messages.timer = setTimeout(function() {
+               messages.validatePoll();
+       }, 1000);
+}
+messages.prototype.startValidatePoll = function() {
+       this.validatecnt = 60;
+       this.validatePoll();
+}
+messages.prototype.stopValidatePoll = function() {
+       clearTimeout(messages.timer);
+}
+messages.prototype.updateInvalidContent = function() {
+       var msg = '';
+       for(key in this.invalids) {
+               var parts = key.split('|');
+               var item = this.invalids[key];
+               if(parts.length == 2) {
+                       msg += 'Message: ' + parts[0] + ' -&gt; ' + parts[1] + 
'<br>';
+                       for(var i = 0; i < item.length; i++) {
+                               msg += item[i] + '<br>';
+                       }
+                       msg += '<br>';
+               }
+               else {
+                       msg += 'Affiliation: ' + parts[2] + '<br>';
+                       msg += 'Message: ' + parts[0] + ' -&gt; ' + parts[1] + 
'<br>';
+                       for(var i = 0; i < item.length; i++) {
+                               msg += item[i] + '<br>';
+                       }
+                       msg += '<br>';
+               }
+       }
+       dojo.byId('invalidmsgfieldcontent').innerHTML = msg;
+       if(dijit.byId('invalidmsgfieldspane').domNode.style.visibility != 
'visible')
+               dijit.byId('invalidmsgfieldspane').show();
+}
+var messages = new messages();



Reply via email to