This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".

The branch, master has been updated
       via  61a9c901e7faf897230ded3a82be9169aab34be2 (commit)
      from  39188655539bdd7661bbe03990b1799e57574a6f (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=61a9c901e7faf897230ded3a82be9169aab34be2

commit 61a9c901e7faf897230ded3a82be9169aab34be2
Author: Stéphane-Eymeric Bredthauer <[email protected]>
Date:   Sun Jun 26 14:57:50 2016 +0200

    Tracker: extrafield dependency

diff --git a/src/common/tracker/Artifact.class.php 
b/src/common/tracker/Artifact.class.php
index a56815d..ae9f774 100644
--- a/src/common/tracker/Artifact.class.php
+++ b/src/common/tracker/Artifact.class.php
@@ -8,6 +8,7 @@
  * Copyright (C) 2009-2013 Alain Peyrat, Alcatel-Lucent
  * Copyright 2012, Thorsten “mirabilos” Glaser <[email protected]>
  * Copyright 2014-2015, Franck Villaume - TrivialDev
+ * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
  *
  * This file is part of FusionForge. FusionForge is free software;
  * you can redistribute it and/or modify it under the terms of the
@@ -1339,6 +1340,43 @@ class Artifact extends FFError {
                                }
                        }
 
+                       // check parent field
+                       if ($type == ARTIFACT_EXTRAFIELDTYPE_SELECT ||
+                                       $type == 
ARTIFACT_EXTRAFIELDTYPE_MULTISELECT ||
+                                       $type == ARTIFACT_EXTRAFIELDTYPE_RADIO 
||
+                                       $type == 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX) {
+                               $allowed = false;
+                               if (!is_null($ef[$efid]['parent']) && 
!empty($ef[$efid]['parent']) && $ef[$efid]['parent']!='100') {
+                                       $aefParentId = $ef[$efid]['parent'];
+                                       $selectedElmnts = 
(isset($extra_fields[$aefParentId]) ? $extra_fields[$aefParentId] : '');
+                                       $aef = new 
ArtifactExtraField($this->ArtifactType,$efid);
+                                       $allowed = 
$aef->getAllowedValues($selectedElmnts);
+                               }
+
+                               if (is_array($allowed)) {
+                                       if (($type == 
ARTIFACT_EXTRAFIELDTYPE_RADIO) || ($type==ARTIFACT_EXTRAFIELDTYPE_SELECT)) {
+                                               if ($extra_fields[$efid]!='100' 
&& !in_array($extra_fields[$efid],$allowed)) {
+                                                       //$aef = new 
ArtifactExtraField($this->ArtifactType,$efid);
+                                                       $aefe = new 
ArtifactExtraFieldElement($aef,$extra_fields[$efid]);
+                                                       
$this->setError(sprintf(_('"%1$s" value of the field "%2$s", is not allowed by 
"%3$s" field values'), $aefe->getName(), $ef[$efid]['field_name'], 
$ef[$aefParentId]['field_name']));
+                                                       return false;
+                                               }
+                                       } else {
+                                               if 
(is_array($extra_fields[$efid])) {
+                                                       //$aef = new 
ArtifactExtraField($this->ArtifactType,$efid);
+                                                       foreach 
($extra_fields[$efid] as $val) {
+                                                               if ($val!='100' 
&& !in_array($val,$allowed)) {
+                                                                       $aefe = 
new ArtifactExtraFieldElement($aef,$val);
+                                                                       
$this->setError(sprintf(_('"%1$s" value of the field "%2$s", is not allowed by 
"%3$s" field values'), $aefe->getName(), $ef[$efid]['field_name'], 
$ef[$aefParentId]['field_name']));
+                                                                       return 
false;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+
+
                        // check pattern for text fields
                        if ($type == ARTIFACT_EXTRAFIELDTYPE_TEXT && 
!empty($ef[$efid]['pattern']) && !empty($extra_fields[$efid]) && 
!preg_match('/'.$ef[$efid]['pattern'].'/', $extra_fields[$efid])) {
                                $this->setError(sprintf(_("Field %s doesn't 
match the pattern."), $ef[$efid]['field_name']));
diff --git a/src/common/tracker/ArtifactExtraField.class.php 
b/src/common/tracker/ArtifactExtraField.class.php
index 4b27804..691f33a 100644
--- a/src/common/tracker/ArtifactExtraField.class.php
+++ b/src/common/tracker/ArtifactExtraField.class.php
@@ -103,9 +103,10 @@ class ArtifactExtraField extends FFError {
         * @param       string  $show100label   The label used for the 100 
value if displayed
         * @param       string  $description    Description used for help text.
         * @param       string  $pattern        A regular expression to check 
the field.
+        * @param       int     $parent         Parent extra field id.
         * @return      bool    true on success / false on failure.
         */
-       function create($name, $field_type, $attribute1, $attribute2, 
$is_required = 0, $alias = '', $show100 = true, $show100label = 'none', 
$description = '', $pattern='') {
+       function create($name, $field_type, $attribute1, $attribute2, 
$is_required = 0, $alias = '', $show100 = true, $show100label = 'none', 
$description = '', $pattern='', $parent=100) {
                //
                //      data validation
                //
@@ -159,8 +160,8 @@ class ArtifactExtraField extends FFError {
                }
 
                db_begin();
-               $result = db_query_params ('INSERT INTO 
artifact_extra_field_list (group_artifact_id, field_name, field_type, 
attribute1, attribute2, is_required, alias, show100, show100label, description, 
pattern)
-                       VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11)',
+               $result = db_query_params ('INSERT INTO 
artifact_extra_field_list (group_artifact_id, field_name, field_type, 
attribute1, attribute2, is_required, alias, show100, show100label, description, 
pattern, parent)
+                       VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12)',
                                           array ($this->ArtifactType->getID(),
                                                          
htmlspecialchars($name),
                                                          $field_type,
@@ -171,7 +172,8 @@ class ArtifactExtraField extends FFError {
                                                          $show100,
                                                          $show100label,
                                                          $description,
-                                                         $pattern));
+                                                         $pattern,
+                                                         $parent));
 
                if ($result && db_affected_rows($result) > 0) {
                        $this->clearError();
@@ -317,6 +319,58 @@ class ArtifactExtraField extends FFError {
        }
 
        /**
+        * getParent - get the parent field id for 
select/multiselect/radio/check field.
+        *
+        * @return      string  The parent.
+        */
+       function getParent() {
+               return $this->data_array['parent'];
+       }
+
+       /**
+        * getChildren - get children fields id for a 
select/multiselect/radio/check field.
+        *
+        * @return      array   Children.
+        */
+       function getChildren() {
+
+               $id = $this->getID();
+               $return = array();
+               $res = db_query_params ('SELECT extra_field_id FROM 
artifact_extra_field_list WHERE parent=$1',
+                               array ($id)) ;
+               if (!$res) {
+                       $this->setError(_('Invalid ArtifactExtraField ID'));
+                       return $return;
+               }
+               while ($row = db_fetch_array($res)) {
+                       $return[] = $row['extra_field_id'];
+               }
+               return $return;
+       }
+
+       /**
+        * getProgeny - get progeny fields id for a 
select/multiselect/radio/check field.
+        *
+        * @return      array   Progeny.
+        */
+       function getProgeny() {
+               $return = array();
+               $childrenArr = $this->getChildren();
+               if (is_array($childrenArr)) {
+                       $return = $childrenArr;
+                       $at = $this->ArtifactType;
+                       foreach ($childrenArr as $child) {
+                               $childObj = new ArtifactExtraField($at,$child);
+                               $childProgenyArr = $childObj->getProgeny();
+                               if (is_array($childProgenyArr)) {
+                                       $return = array_merge($return, 
$childProgenyArr);
+                               }
+                       }
+               }
+               return $return;
+       }
+
+       /**
         * getShow100 - get the show100 field.
         *
         * @return      int     The show100 attribute.
@@ -407,6 +461,49 @@ class ArtifactExtraField extends FFError {
        }
 
        /**
+        * getAllowedValues - Get the list of allowed values for this extra 
field
+        *
+        * @param       string|array    $parentValues   Id or id list of 
selected parent values.
+        * @return      array|bool
+        */
+       function getAllowedValues($parentValues) {
+
+               $parentId = $this->getParent();
+               if ($parentId=='100') {
+                       return false;
+               }
+               if ($this->getType() != ARTIFACT_EXTRAFIELDTYPE_SELECT &&
+                               $this->getType() != 
ARTIFACT_EXTRAFIELDTYPE_MULTISELECT &&
+                               $this->getType() != 
ARTIFACT_EXTRAFIELDTYPE_RADIO &&
+                               $this->getType() != 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX) {
+                       return false;
+               }
+               if (empty($parentValues) || $parentValues=='100') {
+                       return false;
+               }
+
+               if (is_array($parentValues)) {
+                       if (count($parentValues)==1 && 
implode('',$parentValues)=='100' ) {
+                               return false;
+                       }
+                       $res = db_query_params ('SELECT child_element_id FROM 
artifact_extra_field_elements
+                                                                               
INNER JOIN artifact_extra_field_elements_dependencies ON child_element_id = 
element_id
+                                                                               
WHERE extra_field_id=$1 AND parent_element_id IN ($2)',
+                                       array ($this->getID(), implode(', ', 
$parentValues)));
+               } else {
+                       $res = db_query_params ('SELECT child_element_id FROM 
artifact_extra_field_elements
+                                                                               
INNER JOIN artifact_extra_field_elements_dependencies ON child_element_id = 
element_id
+                                                                               
WHERE extra_field_id=$1 AND parent_element_id=$2',
+                                       array ($this->getID(), $parentValues));
+               }
+               $return = array();
+               while ($row = db_fetch_array($res)) {
+                       $return[] = $row['child_element_id'];
+               }
+               return $return;
+       }
+
+       /**
         * update - update a row in the table used to store box names
         * for a tracker.  This function is only to update rowsf
         * for boxes configured by the admin.
@@ -418,9 +515,12 @@ class ArtifactExtraField extends FFError {
         * @param       string  $alias          Alias for this field
         * @param       int     $show100        True or false whether the 100 
value is displayed or not
         * @param       string  $show100label   The label used for the 100 
value if displayed
+        * @param       string  $description    Description used for help text.
+        * @param       string  $pattern        A regular expression to check 
the field.
+        * @param       int     $parent         Parent extra field id.
         * @return      bool    success.
         */
-       function update($name, $attribute1, $attribute2, $is_required = 0, 
$alias = "", $show100 = true, $show100label = 'none', $description = '', 
$pattern='') {
+       function update($name, $attribute1, $attribute2, $is_required = 0, 
$alias = "", $show100 = true, $show100label = 'none', $description = '', 
$pattern='', $parent=100) {
                if (!forge_check_perm ('tracker_admin', 
$this->ArtifactType->Group->getID())) {
                        $this->setPermissionDeniedError();
                        return false;
@@ -432,6 +532,7 @@ class ArtifactExtraField extends FFError {
                        $this->setError(_('A field name is required'));
                        return false;
                }
+
                $res = db_query_params ('SELECT field_name FROM 
artifact_extra_field_list
                                WHERE field_name=$1 AND group_artifact_id=$2 
AND extra_field_id !=$3',
                        array($name,
@@ -450,7 +551,6 @@ class ArtifactExtraField extends FFError {
                if (!($alias = $this->generateAlias($alias,$name))) {
                        return false;
                }
-
                $result = db_query_params ('UPDATE artifact_extra_field_list
                        SET field_name = $1,
                        description = $2,
@@ -461,8 +561,9 @@ class ArtifactExtraField extends FFError {
                        show100 = $7,
                        show100label = $8,
                        pattern = $9,
-                       WHERE extra_field_id = $10
-                       AND group_artifact_id = $11',
+                       parent = $10
+                       WHERE extra_field_id = $11
+                       AND group_artifact_id = $12',
                                           array (htmlspecialchars($name),
                                                          $description,
                                                          $attribute1,
@@ -472,6 +573,7 @@ class ArtifactExtraField extends FFError {
                                                          $show100,
                                                          $show100label,
                                                          $pattern,
+                                                         $parent,
                                                          $this->getID(),
                                                          
$this->ArtifactType->getID())) ;
                if ($result && db_affected_rows($result) > 0) {
diff --git a/src/common/tracker/ArtifactExtraFieldElement.class.php 
b/src/common/tracker/ArtifactExtraFieldElement.class.php
index ac5202a..f6b44c0 100644
--- a/src/common/tracker/ArtifactExtraFieldElement.class.php
+++ b/src/common/tracker/ArtifactExtraFieldElement.class.php
@@ -5,6 +5,7 @@
  * Copyright 2004, Anthony J. Pugliese
  * Copyright 2009, Roland Mas
  * Copyright 2009, Alcatel-Lucent
+ * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
  *
  * This file is part of FusionForge. FusionForge is free software;
  * you can redistribute it and/or modify it under the terms of the
@@ -222,6 +223,114 @@ class ArtifactExtraFieldElement extends FFError {
        }
 
        /**
+        * getParentElements - return the list of the elements of the parent 
field on which depends the current element
+        *
+        * @return      array of parent elements
+        */
+       function getParentElements() {
+               $res = db_query_params ('SELECT parent_element_id
+                               FROM artifact_extra_field_elements_dependencies
+                               WHERE child_element_id=$1',
+                               array($this->getID()));
+               $values = array();
+               while($arr = db_fetch_array($res)) {
+                       $values[] = $arr['parent_element_id'];
+               }
+               return $values;
+       }
+
+       /**
+        * getChildrenElements - return the array of the elements of children 
fields who depend on current element
+        *
+        * @return      array of parent elements
+        */
+       function getChildrenElements($childExtraFieldId = null) {
+               if (is_null($childExtraFieldId)) {
+                       $aefChildren = $this->ArtifactExtraField->getChildren();
+                       $res = db_query_params ('SELECT extra_field_id, 
child_element_id
+                               FROM artifact_extra_field_elements_dependencies
+                               INNER JOIN artifact_extra_field_elements ON 
child_element_id = element_id
+                               WHERE parent_element_id=$1
+                               ORDER BY extra_field_id',
+                                       array($this->getID()));
+               } else {
+                       $aefChildren = array($childExtraFieldId);
+                       $res = db_query_params ('SELECT extra_field_id, 
child_element_id
+                               FROM artifact_extra_field_elements_dependencies
+                               INNER JOIN artifact_extra_field_elements ON 
child_element_id = element_id
+                               WHERE parent_element_id=$1
+                               AND extra_field_id=$2
+                               ORDER BY extra_field_id',
+                                       array($this->getID(),
+                                       $childExtraFieldId));
+               }
+               $values = array();
+               $current = 0;
+               if (is_array($aefChildren)) {
+                       foreach ($aefChildren as $aefChild) {
+                               $values[$aefChild] = array();
+                       }
+                       while($arr = db_fetch_array($res)) {
+                               $values[$arr['extra_field_id']][] = 
$arr['child_element_id'];
+                       }
+               }
+               return $values;
+       }
+       /**
+        * saveParentElements - save the list of the elements of the parent 
field on which depends the current element
+        *
+        * @param       elements        array of new parent elements
+        * @return      bool    always true
+        */
+       function saveParentElements($elements) {
+               $return = true;
+               // Get current parent elements.
+               $currentElements = $this->getParentElements();
+               // Remove parent elements no longer present.
+               foreach ($currentElements as $element) {
+                       if (!in_array($element, $elements)) {
+                               if (!$this->_removeParentElement($element)) {
+                                       $return = false;
+                               }
+                       }
+               }
+               // Add missing required fields.
+               foreach ($elements as $element) {
+                       if (!in_array($element, $currentElements)) {
+                               if (!$this->_addParentElement($element)) {
+                                       $return = false;
+                               }
+                       }
+               }
+               return $return;
+       }
+
+       function _addParentElement($ParentElementId) {
+               $res = db_query_params ('INSERT INTO 
artifact_extra_field_elements_dependencies
+                               (parent_element_id, child_element_id)
+                               VALUES ($1, $2)',
+                               array($ParentElementId,
+                                               $this->getID()));
+               if (!$res) {
+                       $this->setError(sprintf(_('Unable to add Parent Element 
%s for Child Element %s'), $ParentElementId, $this->getID())._(':').' 
'.db_error());
+                       return false;
+               }
+               return true;
+       }
+
+       function _removeParentElement($ParentElementId) {
+               $res = db_query_params ('DELETE FROM 
artifact_extra_field_elements_dependencies
+                               WHERE parent_element_id=$1 AND 
child_element_id=$2',
+                               array($ParentElementId,
+                                               $this->getID()));
+               if (!$res) {
+                       $this->setError(sprintf(_('Unable to remove Parent 
Element %s for Child Element %s'), $ParentElementId, $this->getID())._(':').' 
'.db_error());
+                       return false;
+               }
+               return true;
+       }
+
+       /**
         * update - update rows in the table used to store the choices
         * for a selection box. This function is used only for extra
         * boxes and fields configured by the admin
diff --git a/src/common/tracker/ArtifactType.class.php 
b/src/common/tracker/ArtifactType.class.php
index dd451b9..c071898 100644
--- a/src/common/tracker/ArtifactType.class.php
+++ b/src/common/tracker/ArtifactType.class.php
@@ -8,6 +8,7 @@
  * Copyright (C) 2011 Alain Peyrat - Alcatel-Lucent
  * Copyright 2012, Thorsten “mirabilos” Glaser <[email protected]>
  * Copyright 2014, Franck Villaume - TrivialDev
+ * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
  *
  * This file is part of FusionForge. FusionForge is free software;
  * you can redistribute it and/or modify it under the terms of the
@@ -624,18 +625,18 @@ class ArtifactType extends FFError {
 
                $g = group_get_object(forge_get_config('template_group'));
                if (!$g || !is_object($g)) {
-                       $this->setError('Could Not Get Template Group');
+                       $this->setError(_('Could Not Get Template Group'));
                        return false;
                } elseif ($g->isError()) {
-                       $this->setError('Template Group Error 
'.$g->getErrorMessage());
+                       $this->setError(_('Template Group Error').' 
'.$g->getErrorMessage());
                        return false;
                }
                $at = new ArtifactType($g,$clone_tracker_id);
                if (!$at || !is_object($at)) {
-                       $this->setError('Could Not Get Tracker To Clone');
+                       $this->setError(_('Could Not Get Tracker To Clone'));
                        return false;
                } elseif ($at->isError()) {
-                       $this->setError('Clone Tracker Error 
'.$at->getErrorMessage());
+                       $this->setError(_('Clone Tracker Error').' 
'.$at->getErrorMessage());
                        return false;
                }
                $efs = $at->getExtraFields();
@@ -647,6 +648,8 @@ class ArtifactType extends FFError {
                //      Iterate list of extra fields
                //
                db_begin();
+               $newEFIds = array();
+               $newEFElIds = array();
                foreach ($efs as $ef) {
                        //new field in this tracker
                        $nef = new ArtifactExtraField($this);
@@ -657,11 +660,13 @@ class ArtifactType extends FFError {
                                        $current_ef_todelete->delete(true,true);
                                }
                        }
-                       if 
(!$nef->create(util_unconvert_htmlspecialchars($ef['field_name']), 
$ef['field_type'], $ef['attribute1'], $ef['attribute2'], $ef['is_required'], 
$ef['alias'], $ef['description'], $ef['pattern'])) {
-                               $this->setError('Error Creating New Extra 
Field: '.$nef->getErrorMessage());
+                       if 
(!$nef->create(util_unconvert_htmlspecialchars($ef['field_name']), 
$ef['field_type'], $ef['attribute1'], $ef['attribute2'], $ef['is_required'], 
$ef['alias'], $ef['show100'], $ef['show100label'], $ef['description'], 
$ef['pattern'], 100)) {
+                               $this->setError(_('Error Creating New Extra 
Field')._(':').' '.$nef->getErrorMessage());
                                db_rollback();
                                return false;
                        }
+                       $newEFIds[$ef['extra_field_id']] = $nef->getID();
+                       $newEFElIds[$ef['extra_field_id']] = array();
                        //
                        //      Iterate the elements
                        //
@@ -672,11 +677,60 @@ class ArtifactType extends FFError {
                                $nel = new ArtifactExtraFieldElement($nef);
                                if 
(!$nel->create(util_unconvert_htmlspecialchars($el['element_name']), 
$el['status_id'])) {
                                        db_rollback();
-                                       $this->setError('Error Creating New 
Extra Field Element: '.$nel->getErrorMessage());
+                                       $this->setError(_('Error Creating New 
Extra Field Element')._(':').' '.$nel->getErrorMessage());
                                        return false;
                                }
+                               
$newEFElIds[$ef['extra_field_id']][$el['element_id']] = $nel->getID();
                        }
                }
+               foreach ($newEFIds as $oldEFId=>$newEFId) {
+                       $oef = new ArtifactExtraField($this,$oldEFId);
+                       $nef = new ArtifactExtraField($this,$newEFId);
+                       if ($oef->getParent() != 100) {
+                               $nef->update($nef->getName(),
+                                                       $nef->getAttribute1(),
+                                                       $nef->getAttribute2(),
+                                                       $nef->isRequired(),
+                                                       $nef->getAlias(),
+                                                       $nef->getShow100(),
+                                                       $nef->getShow100label(),
+                                                       $nef->getDescription(),
+                                                       $nef->getPattern(),
+                                                       
$newEFIds[$oef->getParent()]);
+                               if ($nef->isError()) {
+                                       db_rollback();
+                                       $this->setError(_('Error Updating New 
Extra Field Parent')._(':').' '.$nef->getErrorMessage());
+                                       return false;
+                               }
+
+                               foreach ($newEFElIds[$oldEFId] as 
$oldEFElId=>$newEFElId) {
+                                       $oel = new 
ArtifactExtraFieldElement($oef,$oldEFElId);
+                                       if ($oel->isError()) {
+                                               db_rollback();
+                                               
$this->setError($oel->getErrorMessage());
+                                               return false;
+                                       }
+                                       $nel = new 
ArtifactExtraFieldElement($nef,$newEFElId);
+                                       if ($nel->isError()) {
+                                               db_rollback();
+                                               
$this->setError($nel->getErrorMessage());
+                                               return false;
+                                       }
+                                       $oPEls = $oel->getParentElements();
+                                       $nPEls = array();
+                                       foreach ($oPEls as $oPEl) {
+                                               
$nPEls[]=$newEFElIds[$oef->getParent()][$oPEl];
+                                       }
+                                       $nel->saveParentElements($nPEls);
+                                       if ($nel->isError()) {
+                                               db_rollback();
+                                               $this->setError(_('Error Saving 
New Extra Field Parent Elements').' '.$nel->getErrorMessage());
+                                               return false;
+                                       }
+                               }
+                       }
+               }
+
                db_commit();
                return true;
 
diff --git a/src/common/tracker/actions/add.php 
b/src/common/tracker/actions/add.php
index 39d0181..55dcbfe 100644
--- a/src/common/tracker/actions/add.php
+++ b/src/common/tracker/actions/add.php
@@ -31,7 +31,11 @@ global $ath;
 $ath->header(array ('title'=>_('Submit New')));
 
 require_once $gfcommon.'tracker/include/build_submission_form.php';
-artifact_submission_form($ath, $group, $summary, $details, $assigned_to, 
$priority, $extra_fields);
+if (isset($summary)) {
+       artifact_submission_form($ath, $group, $summary, $details, 
$assigned_to, $priority, $extra_fields);
+} else {
+       artifact_submission_form($ath, $group);
+}
 
 $ath->footer();
 
diff --git a/src/common/tracker/actions/admin-updates.php 
b/src/common/tracker/actions/admin-updates.php
index 0537720..4ca6abe 100644
--- a/src/common/tracker/actions/admin-updates.php
+++ b/src/common/tracker/actions/admin-updates.php
@@ -40,6 +40,7 @@ if (getStringFromRequest('add_extrafield')) {
        $attribute1 = getStringFromRequest('attribute1');
        $attribute2 = getStringFromRequest('attribute2');
        $pattern = getStringFromRequest('pattern');
+       $parent = getStringFromRequest('parent');
        $is_required = getStringFromRequest('is_required');
        $alias = getStringFromRequest('alias');
        $hide100 = getStringFromRequest('hide100');
@@ -57,7 +58,7 @@ if (getStringFromRequest('add_extrafield')) {
                } else {
                        $show100 = 1;
                }
-               if (!$ab->create($name, $field_type, $attribute1, $attribute2, 
$is_required, $alias, $show100, $show100label, $description, $pattern)) {
+               if (!$ab->create($name, $field_type, $attribute1, $attribute2, 
$is_required, $alias, $show100, $show100label, $description, $pattern, 
$parent)) {
                        $error_msg .= _('Error inserting a custom field')._(': 
').$ab->getErrorMessage();
                        $ab->clearError();
                } else {
@@ -234,6 +235,7 @@ if (getStringFromRequest('add_extrafield')) {
        $attribute1 = getStringFromRequest('attribute1');
        $attribute2 = getStringFromRequest('attribute2');
        $pattern = getStringFromRequest('pattern');
+       $parent = getStringFromRequest('parent');
        $is_required = getStringFromRequest('is_required');
        $alias = getStringFromRequest('alias');
        $hide100 = getStringFromRequest('hide100');
@@ -250,7 +252,7 @@ if (getStringFromRequest('add_extrafield')) {
                } else {
                        $show100 = 1;
                }
-               if (!$ac->update($name, $attribute1, $attribute2, $is_required, 
$alias, $show100, $show100label, $description, $pattern)) {
+               if (!$ac->update($name, $attribute1, $attribute2, $is_required, 
$alias, $show100, $show100label, $description, $pattern, $parent)) {
                        $error_msg .= _('Update failed')._(': 
').$ac->getErrorMessage();
                        $ac->clearError();
                } else {
@@ -264,8 +266,8 @@ if (getStringFromRequest('add_extrafield')) {
 //
 } elseif (getStringFromRequest('update_opt')) {
        $id = getStringFromRequest('id');
-       $name = getStringFromRequest('name');
        $boxid = getStringFromRequest('boxid');
+       $parentElements = getStringFromRequest('parent_elements');
 
        $ac = new ArtifactExtraField($ath,$boxid);
        if (!$ac || !is_object($ac)) {
@@ -286,7 +288,14 @@ if (getStringFromRequest('add_extrafield')) {
                                $ao->clearError();
                        } else {
                                $feedback .= _('Element updated');
+                               $parentElements = 
getStringFromRequest('parent_elements');
+                               if (!$ao->saveParentElements($parentElements)) {
+                                       $error_msg .= _('Update failed')._(': 
').$ao->getErrorMessage();
+                                       $ao->clearError();
+                               } else {
+                               $feedback .= html_e('br')._('Parent Elements 
updated');
                                $next = 'add_extrafield';
+                               }
                        }
                }
        }
diff --git a/src/common/tracker/include/ArtifactTypeHtml.class.php 
b/src/common/tracker/include/ArtifactTypeHtml.class.php
index 4025972..001084b 100644
--- a/src/common/tracker/include/ArtifactTypeHtml.class.php
+++ b/src/common/tracker/include/ArtifactTypeHtml.class.php
@@ -105,29 +105,37 @@ class ArtifactTypeHtml extends ArtifactType {
 
                $links_arr[]='/tracker/admin/?group_id='.$group_id;
                $title_arr[]=_('New Tracker');
+               $attr_arr[] = array('title'=>_('Create a new tracker.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&update_type=1';
                $title_arr[]=_('Update Settings');
+               $attr_arr[] = array('title'=>_('Set up preferences like 
expiration times, email addresses.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&add_extrafield=1';
                $title_arr[]=_('Manage Custom Fields');
+               $attr_arr[] = array('title'=>_('Add new boxes like Phases, 
Quality Metrics, Components, etc.  Once added they can be used with other 
selection boxes (for example, Categories or Groups) to describe and browse bugs 
or other artifact types.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&workflow=1';
                $title_arr[]=_('Manage Workflow');
+               $attr_arr[] = array('title'=>_('Edit tracker workflow.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&customize_list=1';
                $title_arr[]=_('Customize List');
+               $attr_arr[] = array('title'=>_('Customize display for the 
tracker.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&add_canned=1';
                $title_arr[]=_('Manage Canned Responses');
+               $attr_arr[] = array('title'=>_('Create/change generic response 
messages for the tracker.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&clone_tracker=1';
-               $title_arr[]=_('Clone Tracker');
+               $title_arr[]=_('Apply Template Tracker');
+               $attr_arr[] = array('title'=>_('Duplicate parameters and fields 
from a template trackers in this one.'));
 
                
$links_arr[]='/tracker/admin/?group_id='.$group_id.'&atid='.$this->getID().'&delete=1';
                $title_arr[]=_('Delete');
+               $attr_arr[] = array('title'=>_('Permanently delete this 
tracker.'));
 
-               echo $HTML->printSubMenu($title_arr, $links_arr, array());
+               echo $HTML->printSubMenu($title_arr, $links_arr, $attr_arr);
        }
 
        function adminFooter($params) {
@@ -164,7 +172,6 @@ class ArtifactTypeHtml extends ArtifactType {
                                $mode = '') {
                $efarr = $this->getExtraFields($types);
                //each two columns, we'll reset this and start a new row
-
                $template = $this->getRenderHTML($types, $mode);
 
                if ($mode=='QUERY') {
@@ -193,7 +200,7 @@ class ArtifactTypeHtml extends ArtifactType {
                                if 
(!isset($selected[$efarr[$i]['extra_field_id']]))
                                        $selected[$efarr[$i]['extra_field_id']] 
= '';
 
-                               $value = 
@$selected[$efarr[$i]['extra_field_id']];
+                               $value = 
$selected[$efarr[$i]['extra_field_id']];
 
                                if ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_SELECT ||
                                        $efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
@@ -251,16 +258,30 @@ class ArtifactTypeHtml extends ArtifactType {
                                $efarr[$i]['show100'] = $status_show_100;
                        }
 
+                       if ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_SELECT ||
+                                       $efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX ||
+                                       $efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_RADIO ||
+                                       $efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
+                               $allowed=false;
+                               if (!is_null($efarr[$i]['parent']) && 
!empty($efarr[$i]['parent']) && $efarr[$i]['parent']!='100') {
+                                       $aefParentId = $efarr[$i]['parent'];
+                                       $selectedElmnts = 
(isset($selected[$aefParentId]) ? $selected[$aefParentId] : '');
+                                       $aef = new 
ArtifactExtraField($this,$efarr[$i]['extra_field_id']);
+                                       $allowed = 
$aef->getAllowedValues($selectedElmnts);
+                               }
+                       }
+
                        if ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_SELECT) {
-                               $str = 
$this->renderSelect($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,false,
 $attrs);
+
+                               $str = 
$this->renderSelect($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,$allowed,
 $attrs);
 
                        } elseif ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX) {
 
-                               $str = 
$this->renderCheckbox($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],
 $attrs);
+                               $str = 
$this->renderCheckbox($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],
 $allowed, $attrs);
 
                        } elseif ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_RADIO) {
 
-                               $str = 
$this->renderRadio($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,$text_any,
 $attrs);
+                               $str = 
$this->renderRadio($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],$show_any,
 $text_any, $allowed, $attrs);
 
                        } elseif ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_TEXT ||
                                        $efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_INTEGER) {
@@ -282,7 +303,7 @@ class ArtifactTypeHtml extends ArtifactType {
 
                        } elseif ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_MULTISELECT) {
 
-                               $str = $this->renderMultiSelectBox 
($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],
 $attrs);
+                               $str = 
$this->renderMultiSelectBox($efarr[$i]['extra_field_id'],$selected[$efarr[$i]['extra_field_id']],$efarr[$i]['show100'],$efarr[$i]['show100label'],
 $allowed, $attrs);
 
                        } elseif ($efarr[$i]['field_type'] == 
ARTIFACT_EXTRAFIELDTYPE_STATUS) {
 
@@ -314,6 +335,103 @@ class ArtifactTypeHtml extends ArtifactType {
                        $template = 
str_replace('{$'.$efarr[$i]['field_name'].'}',$str,$template);
                }
                if($template != NULL){
+                       if ($mode == 'UPDATE') {
+                               $jsvariable ="
+       var invalidSelectMsg = '"._("One or more of the selected options is not 
allowed")."';
+       var invalidInputMsg = '". _("This choice is not allowed")."';";
+                               $javascript = <<<'EOS'
+       $.expr[':'].invalid = function(elem, index, match) {
+               for (let invalid of document.querySelectorAll(':invalid') )  {
+                       if (elem === invalid) { return true; }
+               }
+               return false;
+       };
+       $(".with-depcy[name^='extra_fields']").on('change', function(){
+               if ($(this).prop('tagName') == 'SELECT') {
+                       var elmnts = $(this).children('option:selected');
+               } else {
+                       var elmnts = $(this).siblings('input:checked');
+               }
+               elmnts.each(function(i){
+                       var dep = $(this).data("dependency");
+                       if (this.value!='100') {
+                               $(dep).each(function(j, val) {
+                                       
$("select[name^='extra_fields["+val.field+"]']:invalid, 
input[name^='extra_fields["+val.field+"]']:invalid").each(function() {
+                                               this.setCustomValidity("");
+                                               $(this).off("change.invalid");
+                                       });
+                                       
$("select[name^='extra_fields["+val.field+"]'] option").each(function(k,opt){
+                                               if (this.value!='100') {
+                                                       if 
($.inArray(parseInt(this.value),val.elmnt)>-1) {
+                                                               
$(this).prop('disabled', false).removeClass('option_disabled');
+                                                       } else if (i==0) {
+                                                               
$(this).prop('disabled', true);
+                                                               
$(this).addClass('option_disabled');
+                                                       }
+                                               }
+                                       });
+                                       
$("input[name^='extra_fields["+val.field+"]']").each(function(k,opt){
+                                               if (this.value!='100') {
+                                                       if 
($.inArray(parseInt(this.value),val.elmnt)>-1) {
+                                                               
$(this).prop('disabled', false).removeClass($(this).attr('type')+'_disabled');
+                                                       } else if (i==0) {
+                                                               
$(this).prop('disabled', true);
+                                                               
$(this).addClass($(this).attr('type')+'_disabled');
+                                                       }
+                                               }
+                                       });
+                               });
+                       } else {
+                               $(dep.fields).each(function(j, val) {
+                                       
$("select[name^='extra_fields["+val+"]']:invalid, 
input[name^='extra_fields["+val+"]']:invalid").each(function() {
+                                               this.setCustomValidity("");
+                                       });
+                                       
$("select[name^='extra_fields["+val+"]'] 
option.option_disabled").each(function() {
+                                               $(this).prop('disabled', 
false).removeClass('option_disabled');
+                                       });
+                                       
$("input.radio_disable[name^='extra_fields["+val+"]']").each(function() {
+                                               $(this).prop('disabled', 
false).removeClass('radio_disabled');
+                                       });
+                                       
$("input.checkbox_disabled[name^='extra_fields["+val+"]']").each(function() {
+                                               $(this).prop('disabled', 
false).removeClass('checkbox_disabled');
+                                       });
+                               });
+                       }
+               });
+               $("select[name^='extra_fields'] 
option:selected:disabled").parent().each(function() {
+                       
$(this).children('option:selected:disabled').prop('disabled', false);
+                       this.setCustomValidity(invalidSelectMsg);
+                       $(this).on("change.invalid", function() {
+                               
$(this).children('option.option_disabled:not(:disabled):not(:selected)').prop('disabled',
 true);
+                               if 
(!$(this).children('option.option_disabled:selected').length) {
+                                       this.setCustomValidity("");
+                                       $(this).off("change.invalid");
+                               }
+                       });
+               });
+               
$("input[name^='extra_fields']:checked:disabled").each(function() {
+                       $(this).prop('disabled', false);
+                       this.setCustomValidity(invalidInputMsg);
+                       if ($(this).attr('type') == 'radio') {
+                               
$(this).siblings('input[type="radio"]').on("change.invalid", function() {
+                                       
$(this).siblings('input[type="radio"]:invalid').prop('disabled', 
true).addClass('input_disabled').each(function() {
+                                               this.setCustomValidity("");
+                                       });
+                                       
$(this).siblings('input[type="radio"]').off("change.invalid");
+                                       $(this).off("change.invalid");
+                               });
+                       } else {
+                               $(this).on("change.invalid", function() {
+                                       $(this).prop('disabled', true);
+                                       this.setCustomValidity("");
+                                       $(this).off("change.invalid");
+                               });
+                       }
+               });
+       });
+EOS;
+                               echo html_e('script', array( 
'type'=>'text/javascript'), 
'//<![CDATA['."\n".'$(function(){'.$jsvariable."\n".$javascript.'});'."\n".'//]]>');
+                       }
                        echo $template;
                }
        }
@@ -536,13 +654,41 @@ class ArtifactTypeHtml extends ArtifactType {
                        $text_100=_('None');
                }
                $arr = $this->getExtraFieldElements($extra_field_id);
-               $keys = array();
+               $aef = new ArtifactExtraField($this, $extra_field_id);
+               $aefChildren = $aef->getChildren();
+               if (!empty($aefChildren)) {
+                       $attrs['class'] = (empty($attrs['class']) ? 
'':$attrs['class'].' ').'with-depcy';
+               }
                $vals = array();
+               $texts = array();
+               $opt_attrs = array();
+               $attrs_100 = array();
+
                for ($i=0; $i<count($arr); $i++) {
-                       $keys[$i]=$arr[$i]['element_id'];
-                       $vals[$i]=$arr[$i]['element_name'];
+                       $vals[$i]=$arr[$i]['element_id'];
+                       $texts[$i]=$arr[$i]['element_name'];
+                       $opt_attrs[$i]=array();
+                       $aefe = new ArtifactExtraFieldElement($aef, 
$arr[$i]['element_id']);
+                       if (!empty($aefChildren)) {
+                               $cElmntArr = $aefe->getChildrenElements();
+                               if (!empty($cElmntArr))
+                               {
+                                       $dependency = '';
+                                       foreach ($cElmntArr as $key=>$cElmnt) {
+                                               $childField = new 
ArtifactExtraField($this, $key);
+                                               $dependency .= 
(empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', 
$cElmnt).']}';
+                                       }
+                                       $dependency = '['.$dependency.']';
+                                       $opt_attrs[$i]= array( 
'data-dependency'=>$dependency);
+                               }
+                       }
                }
-               return html_build_select_box_from_arrays 
($keys,$vals,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any,
 $allowed, $attrs);
+
+               if ($show_100 && !empty($aefChildren)) {
+                       $attrs_100 = array( 'data-dependency'=>'{"fields": 
['.implode(', ',$aefChildren).']}');
+               }
+
+               return html_build_select_box_from_arrays 
($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any,
 $allowed, $attrs, $opt_attrs, $attrs_100);
        }
 
        /**
@@ -598,15 +744,42 @@ class ArtifactTypeHtml extends ArtifactType {
         * @param       array   $attrs          Array of other attributes
         * @return      string  HTML code using radio buttons
         */
-       function renderRadio 
($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any',
 $attrs = array()) {
+       function renderRadio 
($extra_field_id,$checked='xzxz',$show_100=false,$text_100='none',$show_any=false,$text_any='Any',
 $allowed = false, $attrs = array()) {
+
                $arr = $this->getExtraFieldElements($extra_field_id);
-               $keys = array();
+               $aef = new ArtifactExtraField($this, $extra_field_id);
+               $aefChildren = $aef->getChildren();
+               if (!empty($aefChildren)) {
+                       $attrs['class'] = (empty($attrs['class']) ? 
'':$attrs['class'].' ').'with-depcy';
+               }
+
                $vals = array();
+               $texts = array();
+               $radios_attrs = array();
+               $attrs_100 = array();
+
                for ($i=0; $i<count($arr); $i++) {
-                       $keys[$i]=$arr[$i]['element_id'];
-                       $vals[$i]=$arr[$i]['element_name'];
+                       $vals[$i]=$arr[$i]['element_id'];
+                       $texts[$i]=$arr[$i]['element_name'];
+                       $aefe = new ArtifactExtraFieldElement($aef, 
$arr[$i]['element_id']);
+                       $dependency = '';
+                       if (!empty($aefChildren)) {
+                               $cElmntArr = $aefe->getChildrenElements();
+                               if (!empty($cElmntArr))
+                               {
+                                       foreach ($cElmntArr as $key=>$cElmnt) {
+                                               $childField = new 
ArtifactExtraField($this, $key);
+                                               $dependency .= 
(empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', 
$cElmnt).']}';
+                                       }
+                                       $dependency = '['.$dependency.']';
+                                       
$radios_attrs[$i]['data-dependency']=$dependency;
+                               }
+                       }
                }
-               return html_build_radio_buttons_from_arrays 
($keys,$vals,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any,$attrs);
+               if ($show_100 && !empty($aefChildren)) {
+                       $attrs_100 = array( 'data-dependency'=>'{"fields": 
['.implode(', ',$aefChildren).']}');
+               }
+               return html_build_radio_buttons_from_arrays 
($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,$show_100,$text_100,$show_any,$text_any,$allowed,$attrs,$radios_attrs,$attrs_100);
        }
 
        /**
@@ -619,37 +792,53 @@ class ArtifactTypeHtml extends ArtifactType {
         * @param       array           $attrs          Array of other 
attributes
         * @return      string          radio buttons
         */
-       function renderCheckbox 
($extra_field_id,$checked=array(),$show_100=false,$text_100='none', $attrs = 
array()) {
+       function renderCheckbox 
($extra_field_id,$checked=array(),$show_100=false,$text_100='none', 
$allowed=false, $attrs = array()) {
                if ($text_100 == 'none'){
                        $text_100=_('None');
                }
+
                if (!$checked || !is_array($checked)) {
                        $checked=array();
                }
                if (!empty($attrs['title'])) {
                        $attrs['title'] = util_html_secure($attrs['title']);
                }
+
                $arr = $this->getExtraFieldElements($extra_field_id);
-               $return = '';
-               if ($show_100) {
-                       $chk_attrs = array('type'=>'checkbox', 
'name'=>'extra_fields['.$extra_field_id.'][]', 'id'=>'extra_fields100', 
'value'=>'100');
-                       if (in_array('100', $checked)) {
-                               $chk_attrs['checked']='checked';
-                       }
-                       $return .= html_e('input', 
array_merge($attrs,$chk_attrs));
-                       $return .= html_e('label', 
array_merge(array('for'=>'extra_fields100'), (empty($attrs['title']) ? array() 
: array('title'=>$attrs['title']))), $text_100);
-                       $return .= html_e('br');
+               $aef = new ArtifactExtraField($this, $extra_field_id);
+               $aefChildren = $aef->getChildren();
+               if (!empty($aefChildren)) {
+                       $attrs['class'] = (empty($attrs['class']) ? 
'':$attrs['class'].' ').'with-depcy';
                }
+
+               $texts = array();
+               $vals = array();
+               $chk_attrs = array();
+               $attrs_100 = array();
+
                for ($i=0; $i<count($arr); $i++) {
-                       $chk_attrs = array('type'=>'checkbox', 
'name'=>'extra_fields['.$extra_field_id.'][]', 
'id'=>'extra_fields'.$arr[$i]['element_id'], 'value'=>$arr[$i]['element_id']);
-                       if (in_array($arr[$i]['element_id'],$checked)) {
-                               $chk_attrs['checked']='checked';
+                       $aefe = new ArtifactExtraFieldElement($aef, 
$arr[$i]['element_id']);
+                       $vals[$i] = $arr[$i]['element_id'];
+                       $texts[$i] = $arr[$i]['element_name'];
+                       $chk_attrs[$i] = array();
+                       $dependency = '';
+                       if (!empty($aefChildren)) {
+                               $cElmntArr = $aefe->getChildrenElements();
+                               if (!empty($cElmntArr))
+                               {
+                                       foreach ($cElmntArr as $key=>$cElmnt) {
+                                               $childField = new 
ArtifactExtraField($this, $key);
+                                               $dependency .= 
(empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', 
$cElmnt).']}';
+                                       }
+                                       $dependency = '['.$dependency.']';
+                                       
$chk_attrs[$i]['data-dependency']=$dependency;
+                               }
                        }
-                       $return .= html_e('input', 
array_merge($attrs,$chk_attrs));
-                       $return .= html_e('label', 
array_merge(array('for'=>'extra_fields'.$arr[$i]['element_id']), 
(empty($attrs['title']) ? array() : array('title'=>$attrs['title']))), 
$arr[$i]['element_name']);
-                       $return .= html_e('br');
                }
-               return $return;
+               if ($show_100 && !empty($aefChildren)) {
+                       $attrs_100['data-dependency'] ='{"fields": 
['.implode(', ',$aefChildren).']}';
+               }
+               return 
html_build_checkboxes_from_arrays($vals,$texts,'extra_fields['.$extra_field_id.']',$checked,false,$show_100,$text_100,$allowed,$attrs,$chk_attrs,$attrs_100);
        }
 
        /**
@@ -662,22 +851,47 @@ class ArtifactTypeHtml extends ArtifactType {
         * @param       array           $attrs          Array of other 
attributes
         * @return      string          radio multiselectbox
         */
-       function renderMultiSelectBox 
($extra_field_id,$checked=array(),$show_100=false,$text_100='none', $attrs = 
array()) {
+       function 
renderMultiSelectBox($extra_field_id,$checked=array(),$show_100=false,$text_100='none',
 $allowed=false, $attrs=array()) {
                if (!$checked) {
                        $checked=array();
                }
                if (!is_array($checked)) {
                        $checked = explode(',',$checked);
                }
-               $keys=array();
-               $vals=array();
                $arr = $this->getExtraFieldElements($extra_field_id);
+               $aef = new ArtifactExtraField($this, $extra_field_id);
+               $aefChildren = $aef->getChildren();
+               if (!empty($aefChildren)) {
+                       $attrs['class'] = (empty($attrs['class']) ? 
'':$attrs['class'].' ').'with-depcy';
+               }
+               $vals = array();
+               $texts = array();
+               $opt_attrs = array();
+               $attrs_100 = array();
+
                for ($i=0; $i<count($arr); $i++) {
-                       $keys[]=$arr[$i]['element_id'];
-                       $vals[]=$arr[$i]['element_name'];
+                       $vals[$i]=$arr[$i]['element_id'];
+                       $texts[$i]=$arr[$i]['element_name'];
+                       $aefe = new ArtifactExtraFieldElement($aef, 
$arr[$i]['element_id']);
+                       if (!empty($aefChildren)) {
+                               $cElmntArr = $aefe->getChildrenElements();
+                               if (!empty($cElmntArr))
+                               {
+                                       $dependency = '';
+                                       foreach ($cElmntArr as $key=>$cElmnt) {
+                                               $childField = new 
ArtifactExtraField($this, $key);
+                                               $dependency .= 
(empty($dependency) ? '':', ').'{"field":'.$key.', "elmnt": ['.implode(', ', 
$cElmnt).']}';
+                                       }
+                                       $dependency = '['.$dependency.']';
+                                       $opt_attrs[$i]= array( 
'data-dependency'=>$dependency);
+                               }
+                       }
                }
                $size = min( count($arr)+1, 15);
-               return 
html_build_multiple_select_box_from_arrays($keys,$vals,"extra_fields[$extra_field_id][]",$checked,$size,$show_100,$text_100,
 $attrs);
+               if ($show_100 && !empty($aefChildren)) {
+                       $attrs_100 = array( 'data-dependency'=>'{"fields": 
['.implode(', ',$aefChildren).']}');
+               }
+               return 
html_build_multiple_select_box_from_arrays($vals,$texts,"extra_fields[$extra_field_id][]",$checked,$size,$show_100,$text_100,
 $allowed, $attrs, $opt_attrs, $attrs_100);
        }
 
        /**
diff --git a/src/common/tracker/include/build_submission_form.php 
b/src/common/tracker/include/build_submission_form.php
index 6c3abbf..5965b8d 100644
--- a/src/common/tracker/include/build_submission_form.php
+++ b/src/common/tracker/include/build_submission_form.php
@@ -23,7 +23,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 require_once 'note.php';
-function artifact_submission_form($ath, $group, $summary='', $details='', 
$assigned_to=100, $priority, $extra_fields=array()) {
+function artifact_submission_form($ath, $group, $summary='', $details='', 
$assigned_to=100, $priority=null, $extra_fields=array()) {
        global $HTML;
        /*
                Show the free-form text submitted by the project admin
@@ -77,7 +77,7 @@ function artifact_submission_form($ath, $group, $summary='', 
$details='', $assig
 
        $content = html_e('strong', array(), _('Detailed 
description').utils_requiredField()._(':'));
        $content .= 
notepad_button('document.forms.trackeraddform.details').html_e('br');
-       $content .= html_e('textarea', array('id'=>'tracker-description', 
'required'=>'required', 'name'=>'details', 'rows'=>'20', 'cols'=>'79', 
'title'=>util_html_secure(html_get_tooltip_description('description'))), 
$details);
+       $content .= html_e('textarea', array('id'=>'tracker-description', 
'required'=>'required', 'name'=>'details', 'rows'=>'20', 'cols'=>'79', 
'title'=>util_html_secure(html_get_tooltip_description('description'))), 
$details, false);
        $cells = array();
        $cells[] = array($content, 'colspan'=>'2');
        echo $HTML->multiTableRow(array(), $cells);
diff --git a/src/common/tracker/views/form-addextrafield.php 
b/src/common/tracker/views/form-addextrafield.php
index e392447..4de2cac 100644
--- a/src/common/tracker/views/form-addextrafield.php
+++ b/src/common/tracker/views/form-addextrafield.php
@@ -139,7 +139,7 @@ if ($ath->usesCustomStatuses()) {
 $vals = array_keys($eftypes);
 $texts = array_values($eftypes);
 
-echo html_build_radio_buttons_from_arrays($vals, $texts, 'field_type', '', 
false, '', false ,'', array('required'=>'required') );
+echo html_build_radio_buttons_from_arrays($vals, $texts, 'field_type', '', 
false, '', false ,'', false, array('required'=>'required') );
 echo html_ac(html_ap() - 1);
 
 echo html_ao('p');
@@ -151,6 +151,16 @@ echo html_e('input', array('type'=>'text', 
'name'=>'attribute2', 'value'=>'80',
 echo _('Text Field Pattern');
 echo html_e('input', array('type'=>'text', 'name'=>'pattern', 'value'=>'', 
'size'=>'80', 'maxlength'=>'255')).html_e('br');
 
+$pfarr = $ath->getExtraFields(array(ARTIFACT_EXTRAFIELDTYPE_RADIO, 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX,ARTIFACT_EXTRAFIELDTYPE_SELECT,ARTIFACT_EXTRAFIELDTYPE_MULTISELECT));
+$parentField = array();
+if (is_array($pfarr)) {
+       foreach ($pfarr as $pf) {
+               $parentField[$pf['extra_field_id']] = $pf['field_name'];
+       }
+}
+asort($parentField,SORT_FLAG_CASE | SORT_STRING);
+echo _('Parent Field');
+echo html_build_select_box_from_arrays(array_keys($parentField), 
array_values($parentField), 'parent', null, true, 'none').html_e('br');
 echo _('Hide the default none value');
 echo html_build_checkbox('hide100','',false).html_e('br');
 echo _('Label for the none value');
diff --git a/src/common/tracker/views/form-addextrafieldoption.php 
b/src/common/tracker/views/form-addextrafieldoption.php
index 6234a56..6182953 100644
--- a/src/common/tracker/views/form-addextrafieldoption.php
+++ b/src/common/tracker/views/form-addextrafieldoption.php
@@ -61,11 +61,11 @@ global $HTML;
                                        if ($efType == 
ARTIFACT_EXTRAFIELDTYPE_STATUS) {
                                                $cells[] = 
array($ath->getStatusName($efearr[$i]['status_id']));
                                        }
-                                       $content = 
util_make_link('/tracker/admin/?group_id='.$group_id.'&atid='.$ath->getID().'&boxid='.$boxid.'&id='.$efearr[$i]['element_id'].'&updownorder_opt=1&new_pos='.(($i
 == 0)? $i + 1 : $i), html_image('ic/btn_up.png','19','18',array('alt'=>'Up')));
-                                       $content .= 
util_make_link('/tracker/admin/?group_id='.$group_id.'&atid='.$ath->getID().'&boxid='.$boxid.'&id='.$efearr[$i]['element_id'].'&updownorder_opt=1&new_pos='.(($i
 == $rows - 1)? $i + 1 : $i + 2), 
html_image('ic/btn_down.png','19','18',array('alt'=>'Down')));
+                                       $content = 
util_make_link('/tracker/admin/?group_id='.$group_id.'&atid='.$ath->getID().'&boxid='.$boxid.'&id='.$efearr[$i]['element_id'].'&updownorder_opt=1&new_pos='.(($i
 == 0)? $i + 1 : $i), html_image('ic/btn_up.png','19','18',array('alt'=>'Up', 
'title'=>_('Move Up this custom field element'))));
+                                       $content .= 
util_make_link('/tracker/admin/?group_id='.$group_id.'&atid='.$ath->getID().'&boxid='.$boxid.'&id='.$efearr[$i]['element_id'].'&updownorder_opt=1&new_pos='.(($i
 == $rows - 1)? $i + 1 : $i + 2), 
html_image('ic/btn_down.png','19','18',array('alt'=>'Down', 'title'=>_('Move 
Down this custom field element'))));
                                        $cells[] = array($content, 
'class'=>'align-center');
                                        $cells[] = 
array($efearr[$i]['element_name']);
-                                       $content = 
util_make_link('/tracker/admin/?update_opt=1&id='.$efearr[$i]['element_id'].'&boxid='.$boxid.'&group_id='.$group_id.'&atid='.
 $ath->getID(), 
html_image('ic/forum_edit.gif','37','15',array('alt'=>_('Edit'))));
+                                       $content = 
util_make_link('/tracker/admin/?update_opt=1&id='.$efearr[$i]['element_id'].'&boxid='.$boxid.'&group_id='.$group_id.'&atid='.
 $ath->getID(), html_image('ic/configure.png','22','22',array('alt'=>_('Edit'), 
'title'=>_('Edit custom field element'))));
                                        $cells[] = array($content, 
'class'=>'align-center');
                                        echo $HTML->multiTableRow($row_attrs, 
$cells);
                                }
diff --git a/src/common/tracker/views/form-updateextrafield.php 
b/src/common/tracker/views/form-updateextrafield.php
index c547e4d..2a36247 100644
--- a/src/common/tracker/views/form-updateextrafield.php
+++ b/src/common/tracker/views/form-updateextrafield.php
@@ -4,6 +4,7 @@
  *
  * Copyright 2010 (c) FusionForge Team
  * Copyright 2014-2015, Franck Villaume - TrivialDev
+ * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
  * http://fusionforge.org
  *
  * This file is part of FusionForge. FusionForge is free software;
@@ -59,21 +60,22 @@ if (!$ac || !is_object($ac)) {
        echo html_ac(html_ap() - 1);
 
        echo html_ao('p');
-       if ($ac->getType() == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
+       $efType=$ac->getType();
+       if ($efType == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
                echo html_e('label', array('for'=>'attribute1'), html_e('b', 
array(), _('Text Area Columns')).html_e('br'));
                echo html_e('input', array('type'=>'text', 'id'=>'attribute1', 
'name'=>'attribute1', 'value'=>$ac->getAttribute1(), 'size'=>'2', 
'maxlength'=>'2'));
                echo html_ac(html_ap() - 1);
                echo html_ao('p');
                echo html_e('label', array('for'=>'attribute2'), html_e('b', 
array(), _('Text Area Columns')).html_e('br'));
                echo html_e('input', array('type'=>'text', 'id'=>'attribute2', 
'name'=>'attribute2', 'value'=>$ac->getAttribute2(), 'size'=>'2', 
'maxlength'=>'2'));
-       } elseif ($ac->getType() == ARTIFACT_EXTRAFIELDTYPE_TEXT || 
$ac->getType() == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
+       } elseif ($efType == ARTIFACT_EXTRAFIELDTYPE_TEXT || $efType == 
ARTIFACT_EXTRAFIELDTYPE_RELATION) {
                echo html_e('label', array('for'=>'attribute1'), html_e('b', 
array(), _('Text Field Size')).html_e('br'));
                echo html_e('input', array('type'=>'text', 'id'=>'attribute1', 
'name'=>'attribute1', 'value'=>$ac->getAttribute1(), 'size'=>'2', 
'maxlength'=>'2'));
                echo html_ac(html_ap() - 1);
                echo html_ao('p');
                echo html_e('label', array('for'=>'attribute2'), html_e('b', 
array(), _('Text Field Maxlength')).html_e('br'));
                echo html_e('input', array('type'=>'text', 'id'=>'attribute2', 
'name'=>'attribute2', 'value'=>$ac->getAttribute2(), 'size'=>'2', 
'maxlength'=>'2'));
-               if ($ac->getType() == ARTIFACT_EXTRAFIELDTYPE_TEXT) {
+               if ($efType == ARTIFACT_EXTRAFIELDTYPE_TEXT) {
                        echo html_ac(html_ap() - 1);
                        echo html_ao('p');
                        echo html_e('label', array('for'=>'pattern'), 
html_e('b', array(), _('Text Field Pattern')).html_e('br'));
@@ -82,6 +84,22 @@ if (!$ac || !is_object($ac)) {
        } else {
                echo html_e('input', array('type'=>'hidden', 
'name'=>'attribute1', 'value'=>'0'));
                echo html_e('input', array('type'=>'hidden', 
'name'=>'attribute2', 'value'=>'0'));
+               if (in_array($efType, array(ARTIFACT_EXTRAFIELDTYPE_RADIO, 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX,ARTIFACT_EXTRAFIELDTYPE_SELECT,ARTIFACT_EXTRAFIELDTYPE_MULTISELECT)))
 {
+                       $pfarr = 
$ath->getExtraFields(array(ARTIFACT_EXTRAFIELDTYPE_RADIO, 
ARTIFACT_EXTRAFIELDTYPE_CHECKBOX,ARTIFACT_EXTRAFIELDTYPE_SELECT,ARTIFACT_EXTRAFIELDTYPE_MULTISELECT));
+                       $parentField = array();
+                       $progenyField = $ac->getProgeny();
+                       if (is_array($pfarr)) {
+                               foreach ($pfarr as $pf) {
+                                       if ($pf['extra_field_id'] != $id && 
!in_array($pf['extra_field_id'], $progenyField))
+                                       $parentField[$pf['extra_field_id']] = 
$pf['field_name'];
+                               }
+                       }
+                       asort($parentField,SORT_FLAG_CASE | SORT_STRING);
+                       echo html_ao('p');
+                       echo html_e('label', array('for'=>'parent'), 
html_e('strong', array(), _('Parent Field')._(':')).html_e('br'));
+                       echo 
html_build_select_box_from_arrays(array_keys($parentField), 
array_values($parentField), 'parent', $ac->getParent(), true, 
'none').html_e('br');
+                       echo html_ac(html_ap() - 1);
+               }
                echo html_e('label', array('for'=>'hide100'), html_e('b', 
array(), _('Hide the default none value')).html_e('br'));
                echo html_build_checkbox('hide100','',!$ac->getShow100());
                echo html_ac(html_ap() - 1);
diff --git a/src/common/tracker/views/form-updateextrafieldelement.php 
b/src/common/tracker/views/form-updateextrafieldelement.php
index 328886b..6af9164 100644
--- a/src/common/tracker/views/form-updateextrafieldelement.php
+++ b/src/common/tracker/views/form-updateextrafieldelement.php
@@ -4,6 +4,7 @@
  *
  * Copyright 2010 (c) FusionForge Team
  * Copyright 2014-2015, Franck Villaume - TrivialDev
+ * Copyright 2016, Stéphane-Eymeric Bredthauer - TrivialDev
  * http://fusionforge.org
  *
  * This file is part of FusionForge. FusionForge is free software;
@@ -46,30 +47,31 @@ if (!$ac || !is_object($ac)) {
        } else {
                $title = sprintf(_('Update a custom field element in %s'), 
$ath->getName()) ;
                $ath->adminHeader(array('title'=>$title));
-
-?>
-                       <h2><?php echo _('Custom Field Name')._(': 
').$ac->getName() ?></h2>
-               <?php
+               echo html_e('h2', array(),  _('Custom Field Name')._(': 
').$ac->getName());
                echo $HTML->openForm(array('action' => 
'/tracker/admin/?group_id='.$group_id.'&atid='.$ath->getID(), 'method' => 
'post'));
-               ?>
-                       <input type="hidden" name="update_opt" value="y" />
-                       <input type="hidden" name="id" value="<?php echo 
$ao->getID(); ?>" />
-                       <input type="hidden" name="boxid" value="<?php echo 
$boxid; ?>" />
-
-                       <p>
-                       <label for="name">
-                       <strong><?php echo _('Element')._(':'); ?></strong><br 
/>
-                       </label>
-                       <input id="name" type="text" name="name" value="<?php 
echo $ao->getName(); ?>" />
-                       </p>
-                       <!--
-                       Show a pop-up box to choose the possible statuses that 
this element will map to
-                       -->
-                       <?php if ($ac->getType() == 
ARTIFACT_EXTRAFIELDTYPE_STATUS) { ?>
-                       <strong><?php echo _('Status'); ?></strong><br />
-                       <?php echo 
$ath->statusBox('status_id',$ao->getStatusID(),false,false);
+               echo html_e('input', array('type'=>'hidden', 
'name'=>'update_opt', 'value'=>'y'));
+               echo html_e('input', array('type'=>'hidden', 'name'=>'id', 
'value'=>$ao->getID()));
+               echo html_e('input', array('type'=>'hidden', 'name'=>'boxid', 
'value'=>$boxid));
+               echo html_ao('p');
+               echo html_e('label', array('for'=>'name'), html_e('strong', 
array(), _('Element')._(':')).html_e('br'));
+               echo html_e('input', array('type'=>'text', 'id'=>'name', 
'name'=>'name', 'value'=>$ao->getName()));
+               echo html_ac(html_ap()-1);
+               // Show a pop-up box to choose the possible statuses that this 
element will map to
+               if ($ac->getType() == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
+                       echo html_e('strong',array(),_('Status')).html_e('br');
+                       echo 
$ath->statusBox('status_id',$ao->getStatusID(),false,false);
+               }
+               if ($ac->getParent()!=100) {
+                       echo html_e('strong',array(),_('Select Parent 
Values')._(':')).html_e('br');
+                       
$parentFieldElmntsArr=$ath->getExtraFieldElements($ac->getParent());
+                       $parentFieldElmntVals=array();
+                       foreach ($parentFieldElmntsArr as $parentFieldElmnt) {
+                               
$parentFieldElmntVals[$parentFieldElmnt['element_id']] = 
$parentFieldElmnt['element_name'];
                        }
-                       echo $HTML->warning_msg(_('It is not recommended that 
you change the custom field name because other things are dependent upon it. 
When you change the custom field name, all related items will be changed to the 
new name.'));
+                       $checkedElmntsArr = $ao->getParentElements();
+                       echo 
html_build_checkboxes_from_array($parentFieldElmntVals, 'parent_elements', 
$checkedElmntsArr, true);
+               }
+               echo $HTML->warning_msg(_('It is not recommended that you 
change the custom field name because other things are dependent upon it. When 
you change the custom field name, all related items will be changed to the new 
name.'));
                        ?>
                        <p>
                        <input type="submit" name="post_changes" value="<?php 
echo _('Update') ?>" /></p>
diff --git a/src/db/20160604-artifact_extra_field_list-parent.sql 
b/src/db/20160604-artifact_extra_field_list-parent.sql
new file mode 100644
index 0000000..e4bceaa
--- /dev/null
+++ b/src/db/20160604-artifact_extra_field_list-parent.sql
@@ -0,0 +1,2 @@
+ALTER TABLE artifact_extra_field_list
+   ADD COLUMN parent integer NOT NULL DEFAULT 100;
\ No newline at end of file
diff --git a/src/db/20160606-artifact_extra_field_elements_dependencies.sql 
b/src/db/20160606-artifact_extra_field_elements_dependencies.sql
new file mode 100644
index 0000000..25e8244
--- /dev/null
+++ b/src/db/20160606-artifact_extra_field_elements_dependencies.sql
@@ -0,0 +1,12 @@
+CREATE TABLE artifact_extra_field_elements_dependencies
+(
+  parent_element_id integer NOT NULL,
+  child_element_id integer NOT NULL,
+  CONSTRAINT artifact_extra_field_elements_dependencies_pkey PRIMARY KEY 
(parent_element_id, child_element_id),
+  CONSTRAINT artifact_extra_field_elements_parent_element_id FOREIGN KEY 
(parent_element_id)
+      REFERENCES artifact_extra_field_elements (element_id) MATCH FULL
+      ON DELETE CASCADE,
+  CONSTRAINT artifact_extra_field_elements_child_element_id FOREIGN KEY 
(child_element_id)
+      REFERENCES artifact_extra_field_elements (element_id) MATCH FULL
+      ON DELETE CASCADE
+);
\ No newline at end of file
diff --git a/src/www/include/html.php b/src/www/include/html.php
index b37037d..f633c92 100644
--- a/src/www/include/html.php
+++ b/src/www/include/html.php
@@ -310,7 +310,8 @@ function html_build_select_box_from_array($vals, 
$select_name, $checked_val = 'x
  */
 function html_build_radio_buttons_from_arrays($vals, $texts, $select_name, 
$checked_val = 'xzxz',
                                                                                
          $show_100 = true, $text_100 = 'none', $show_any = false,
-                                                                               
          $text_any = 'any', $attrs = array()) {
+                                                                               
          $text_any = 'any', $allowed = false, $attrs = array(),
+                                                                               
          $radios_attrs = array(), $attrs_100 = array()) {
 
        $attrs['type'] = 'radio';
        $attrs['name'] = $select_name;
@@ -338,6 +339,9 @@ function html_build_radio_buttons_from_arrays($vals, 
$texts, $select_name, $chec
        //we don't always want the default 100 row shown
        if ($show_100) {
                $radio_attrs = $attrs;
+               if (!empty($attrs_100)) {
+                       $radio_attrs = array_merge($radio_attrs, $attrs_100);
+               }
                $radio_attrs['value'] = '100';
                $radio_attrs['id'] = $select_name.'_100';
                if ($checked_val == '100') {
@@ -357,10 +361,16 @@ function html_build_radio_buttons_from_arrays($vals, 
$texts, $select_name, $chec
                        $radio_attrs['id'] = $select_name.'_'.$vals[$i];
                        if ((string)$vals[$i] == (string)$checked_val) {
                                $checked_found = true;
-                               //$return .= ' checked="checked"';
                                $radio_attrs ['checked'] = 'checked';
                        }
-                               $return .= html_e('input', 
$radio_attrs).html_e('label',array('for'=>$select_name.'_'.$vals[$i]), 
htmlspecialchars($texts[$i])).html_e('br');
+                       if (is_array($allowed) && !in_array($vals[$i], 
$allowed)) {
+                               $radio_attrs['disabled'] = 'disabled';
+                               $radio_attrs['class'] = 
(isset($radio_attrs['class']) ? $radio_attrs['class'].' ':'').'radio_disabled';
+                       }
+                       if (isset($radios_attrs[$i]) && 
is_array($radios_attrs[$i])) {
+                               $radio_attrs = array_merge($radio_attrs, 
$radios_attrs[$i]);
+                       }
+                       $return .= html_e('input', 
$radio_attrs).html_e('label',array('for'=>$select_name.'_'.$vals[$i]), 
htmlspecialchars($texts[$i])).html_e('br');
                }
        }
        //
@@ -569,7 +579,8 @@ function html_use_jquerybrowser() {
 function html_build_select_box_from_arrays($vals, $texts, $select_name, 
$checked_val = 'xzxz',
                                                                                
   $show_100 = true, $text_100 = 'none',
                                                                                
   $show_any = false, $text_any = 'any',
-                                                                               
   $allowed = false, $attrs = array()) {
+                                                                               
   $allowed = false, $attrs = array(),
+                                                                               
   $opts_attrs = array(), $attrs_100 = array()) {
        if ($text_100 == 'none') {
                $text_100 = _('None');
        }
@@ -615,6 +626,9 @@ function html_build_select_box_from_arrays($vals, $texts, 
$select_name, $checked
                        $text_100 = _('None');
                }
                $opt_attrs = array('value' => 100);
+               if (!empty($attrs_100)) {
+                       $opt_attrs = array_merge($opt_attrs, $attrs_100);
+               }
                if ($checked_val)
                        $opt_attrs['selected'] = 'selected';
                $return .= html_e('option', $opt_attrs, 
util_html_secure($text_100), false);
@@ -635,7 +649,10 @@ function html_build_select_box_from_arrays($vals, $texts, 
$select_name, $checked
                        }
                        if (is_array($allowed) && !in_array($vals[$i], 
$allowed)) {
                                $opt_attrs['disabled'] = 'disabled';
-                               $opt_attrs['class'] = 'option_disabled';
+                               $opt_attrs['class'] = 
(isset($opt_attrs['class']) ? $opt_attrs['class'].' ':'').'option_disabled';
+                       }
+                       if (isset($opts_attrs[$i]) && 
is_array($opts_attrs[$i])) {
+                               $opt_attrs = array_merge($opt_attrs, 
$opts_attrs[$i]);
                        }
                        $return .= html_e('option', $opt_attrs, 
util_html_secure($texts[$i]));
                        $have_a_subelement = true;
@@ -646,7 +663,7 @@ function html_build_select_box_from_arrays($vals, $texts, 
$select_name, $checked
        //      we want to preserve that value UNLESS that value was 'xzxz', 
the default value
        //
        if (!$checked_found && $checked_val != 'xzxz' && $checked_val && 
$checked_val != 100) {
-               $return .= html_e('option', array('value' => 
util_html_secure($checked_val), 'selected' => 'selected'), _('No Change'), 
false);
+               $return .= html_e('option', array_merge(array('value' => 
util_html_secure($checked_val), 'selected' => 'selected'), 
$opts_attrs[$checked_val]), _('No Change'), false);
                $have_a_subelement = true;
        }
 
@@ -752,9 +769,8 @@ function html_build_multiple_select_box($result, $name, 
$checked_array, $size =
  * @param      array   $attrs          Array of other attributes for this 
select element
  * @return     string
  */
-function html_build_multiple_select_box_from_arrays($vals, $texts, $name, 
$checked_array, $size = 8, $show_100 = true, $text_100 = 'none', $attrs = 
array()) {
-       $checked_count = count($checked_array);
-       $return = html_ao('select', array('name' => $name, 'multiple' => 
'multiple', 'size' => $size));
+function html_build_multiple_select_box_from_arrays($vals, $texts, $name, 
$checked_array, $size = 8, $show_100 = true, $text_100 = 'none', $allowed = 
false, $attrs = array(), $opts_attrs = array(), $attrs_100 = array()) {
+       $return = html_ao('select', array_merge(array('name' => $name, 
'multiple' => 'multiple', 'size' => $size), $attrs));
        if ($show_100) {
                if ($text_100 == 'none') {
                        $text_100 = _('None');
@@ -763,10 +779,11 @@ function 
html_build_multiple_select_box_from_arrays($vals, $texts, $name, $check
                        Put in the default NONE box
                */
                $opt_attrs = array('value' => 100);
-               for ($j = 0; $j < $checked_count; $j++) {
-                       if ($checked_array[$j] == '100') {
-                               $opt_attrs['selected'] = 'selected';
-                       }
+               if (!empty($attrs_100)) {
+                       $opt_attrs = array_merge($opt_attrs, $attrs_100);
+               }
+               if (in_array('100', $checked_array)) {
+                       $opt_attrs['selected'] = 'selected';
                }
                $return .= html_e('option', $opt_attrs, $text_100, false);
        }
@@ -775,15 +792,19 @@ function 
html_build_multiple_select_box_from_arrays($vals, $texts, $name, $check
        for ($i = 0; $i < $rows; $i++) {
                if (($vals[$i] != '100') || ($vals[$i] == '100' && !$show_100)) 
{
                        $opt_attrs = array();
-                       $opt_attrs = array('value' => $vals[$i]);
+                       $opt_attrs['value'] = $vals[$i];
                        /*
                                Determine if it's checked
                        */
-                       $val = $vals[$i];
-                       for ($j = 0; $j < $checked_count; $j++) {
-                               if ($val == $checked_array[$j]) {
-                                       $opt_attrs['selected'] = 'selected';
-                               }
+                       if (in_array($vals[$i], $checked_array)) {
+                               $opt_attrs['selected'] = 'selected';
+                       }
+                       if (isset($opts_attrs[$i]) && 
is_array($opts_attrs[$i])) {
+                               $opt_attrs = array_merge($opt_attrs, 
$opts_attrs[$i]);
+                       }
+                       if (is_array($allowed) && !in_array($vals[$i], 
$allowed)) {
+                               $opt_attrs['disabled'] = 'disabled';
+                               $opt_attrs['class'] = 
(isset($opt_attrs['class']) ? $opt_attrs['class'].' ':'').'option_disabled';
                        }
                        $return .= html_e('option', $opt_attrs, $texts[$i], 
false);
                }
@@ -818,7 +839,21 @@ function html_build_checkbox($name, $value, $checked, 
$attrs=array()) {
  * @param      array   $attrs          Array of other attributes for this 
element
  * @return     html code for checkbox control
  */
-function html_build_checkboxes_from_array($vals, $check_name, 
$checked_array=array(), $checkall=false, $attrs=array()) {
+function html_build_checkboxes_from_array($vals, $check_name, 
$checked=array(), $checkall=false, $show_100) {
+       $values = array_keys($vals);
+       $texts =  array_values($vals);
+       return html_build_checkboxes_from_arrays($values, $texts, $check_name, 
$checked, $checkall, false);
+}
+
+function html_build_checkboxes_from_arrays($vals, $texts, $check_name, 
$checked=array(), $checkall=false, $show_100=true, $text_100='none', 
$allowed=false, $attrs=array(),$checkbox_attrs=array(),$attrs_100=array()) {
+       if ($text_100 == 'none') {
+               $text_100 = _('None');
+       }
+       $return = '';
+       $rows = count($vals);
+       if (count($texts) != $rows) {
+               $return .= 'Error: uneven row counts';
+       }
 
        $title = (empty($attrs['title']) ? array() : array('title' => 
$attrs['title']));
        if ($checkall) {
@@ -829,20 +864,37 @@ function html_build_checkboxes_from_array($vals, 
$check_name, $checked_array=arr
                                                                });
                                                        });
                                                //]]';
-               echo html_e('script', array( 'type'=>'text/javascript'), 
$javascript);
-               echo html_ao('p');
-               echo html_e('input', array_merge( array( 'type' => 'checkbox', 
'name' => 'checkall_'.$check_name, 'id' => 'checkall_'.$check_name ), $attrs));
-               echo html_e('label', array_merge( array( 'for' => 
'checkall_'.$check_name), $title), _('Check all'), false);
-               echo html_ac(html_ap() - 1);
-       }
-       echo html_ao('p');
-       foreach ($vals as $key => $value) {
-               $checked = ((in_array($key, $checked_array)) ? 
array('checked'=>'checked') : array());
-               echo html_e('input', array_merge( array( 'type' => 'checkbox', 
'name' => $check_name.'[]', 'id' => $check_name.$key, 'value' => $key), $attrs, 
$checked));
-               echo html_e('label', array_merge( array( 'for' => 
$check_name.$key), $title), $value, false);
-               echo html_e('br');
-       }
-       echo html_ac(html_ap() - 1);
+               $return .= html_e('script', array( 'type'=>'text/javascript'), 
$javascript);
+               $return .= html_ao('p');
+               $return .= html_e('input', array_merge( array( 'type' => 
'checkbox', 'name' => 'checkall_'.$check_name, 'id' => 'checkall_'.$check_name 
), $attrs));
+               $return .= html_e('label', array_merge( array( 'for' => 
'checkall_'.$check_name), $title), _('Check all'), false);
+               $return .= html_ac(html_ap() - 1);
+       }
+       $return .= html_ao('p');
+
+       if ($show_100) {
+               if (in_array('100', $checked)) {
+                       $attrs_100['checked']='checked';
+               }
+               $return .= html_e('input', array_merge( array( 'type' => 
'checkbox', 'name' => $check_name.'[]', 'id' => $check_name.'_100', 'value' => 
100), $attrs, $attrs_100));
+               $return .= html_e('label', array_merge( array( 'for' => 
$check_name.'_100'), $title), $text_100, false);
+               $return .= html_e('br');
+       }
+
+       for ($i = 0; $i < $rows; $i++)  {
+               if (in_array($vals[$i], $checked)) {
+                       $checkbox_attrs[$i]['checked']='checked';
+               }
+               if ($allowed && !in_array($vals[$i], $allowed)) {
+                       $checkbox_attrs[$i]['disabled'] = 'disabled';
+                       $checkbox_attrs[$i]['class'] = 
(isset($checkbox_attrs[$i]['class']) ? $checkbox_attrs[$i]['class'].' ' : 
'').'checkbox_disabled';
+               }
+               $return .= html_e('input', array_merge( array( 'type' => 
'checkbox', 'name' => $check_name.'[]', 'id' => $check_name.'_'.$vals[$i], 
'value' => $vals[$i]), $attrs, (isset($checkbox_attrs[$i]) ? 
$checkbox_attrs[$i] : array())));
+               $return .= html_e('label', array_merge( array( 'for' => 
$check_name.'_'.$vals[$i]), $title), $texts[$i], false);
+               $return .= html_e('br');
+       }
+       $return .= html_ac(html_ap() - 1);
+       return $return;
 }
 
 /**
@@ -851,7 +903,7 @@ function html_build_checkboxes_from_array($vals, 
$check_name, $checked_array=arr
  * @see html_build_priority_select_box()
  */
 function build_priority_select_box($name = 'priority', $checked_val = '3', 
$nochange = false, $attrs = array()) {
-       echo html_build_priority_select_box($name, $checked_val, $nochange, 
$attrs);
+       return  html_build_priority_select_box($name, $checked_val, $nochange, 
$attrs);
 }
 
 /**
@@ -1210,6 +1262,7 @@ function html_e($name, $attrs = array(), $content = "", 
$shortform = true, $inde
                }
                $rv .= ' '.$key.'="'.util_html_secure($value).'"';
        }
+
        if ($content === "" && $shortform) {
                $rv .= ' />';
                if ($indent) $rv .= "\n";

-----------------------------------------------------------------------

Summary of changes:
 src/common/tracker/Artifact.class.php              |  38 +++
 src/common/tracker/ArtifactExtraField.class.php    | 118 ++++++++-
 .../tracker/ArtifactExtraFieldElement.class.php    | 109 ++++++++
 src/common/tracker/ArtifactType.class.php          |  68 ++++-
 src/common/tracker/actions/add.php                 |   6 +-
 src/common/tracker/actions/admin-updates.php       |  15 +-
 .../tracker/include/ArtifactTypeHtml.class.php     | 294 ++++++++++++++++++---
 .../tracker/include/build_submission_form.php      |   4 +-
 src/common/tracker/views/form-addextrafield.php    |  12 +-
 .../tracker/views/form-addextrafieldoption.php     |   6 +-
 src/common/tracker/views/form-updateextrafield.php |  24 +-
 .../tracker/views/form-updateextrafieldelement.php |  46 ++--
 .../20160604-artifact_extra_field_list-parent.sql  |   2 +
 ...-artifact_extra_field_elements_dependencies.sql |  12 +
 src/www/include/html.php                           | 123 ++++++---
 15 files changed, 752 insertions(+), 125 deletions(-)
 create mode 100644 src/db/20160604-artifact_extra_field_list-parent.sql
 create mode 100644 
src/db/20160606-artifact_extra_field_elements_dependencies.sql


hooks/post-receive
-- 
FusionForge

_______________________________________________
Fusionforge-commits mailing list
[email protected]
http://lists.fusionforge.org/cgi-bin/mailman/listinfo/fusionforge-commits

Reply via email to