diff --git a/CRM/Activity/BAO/Activity.php b/CRM/Activity/BAO/Activity.php index 247fff530176..48893a169fb0 100644 --- a/CRM/Activity/BAO/Activity.php +++ b/CRM/Activity/BAO/Activity.php @@ -2498,7 +2498,7 @@ public static function getContactActivitySelector(&$params) { $activity = array(); $activity['DT_RowId'] = $activityId; // Add class to this row if overdue. - $activity['DT_RowClass'] = 'crm-entity'; + $activity['DT_RowClass'] = "crm-entity status-id-{$values['status_id']}"; if (CRM_Utils_Date::overdue(CRM_Utils_Array::value('activity_date_time', $values)) && CRM_Utils_Array::value('status_id', $values) == 1 ) { diff --git a/CRM/Activity/Form/Activity.php b/CRM/Activity/Form/Activity.php index 5d2d1fd8a4de..1cacf389983b 100644 --- a/CRM/Activity/Form/Activity.php +++ b/CRM/Activity/Form/Activity.php @@ -544,7 +544,7 @@ public function setDefaultValues() { $defaults['assignee_contact_id'] = CRM_Utils_Array::value('assignee_contact', $defaults); // set default tags if exists - $defaults['tag'] = CRM_Core_BAO_EntityTag::getTag($this->_activityId, 'civicrm_activity'); + $defaults['tag'] = implode(',', CRM_Core_BAO_EntityTag::getTag($this->_activityId, 'civicrm_activity')); } else { // if it's a new activity, we need to set default values for associated contact fields @@ -725,13 +725,10 @@ public function buildQuickForm() { $this->assign('customDataSubType', $this->_activityTypeId); $this->assign('entityID', $this->_activityId); - CRM_Core_BAO_Tag::getTags('civicrm_activity', $tags, NULL, - ' ', TRUE); + $tags = CRM_Core_BAO_Tag::getColorTags('civicrm_activity'); if (!empty($tags)) { - $this->add('select', 'tag', ts('Tags'), $tags, FALSE, - array('id' => 'tags', 'multiple' => 'multiple', 'class' => 'crm-select2 huge') - ); + $this->add('select2', 'tag', ts('Tags'), $tags, FALSE, array('class' => 'huge', 'placeholder' => ts('- select -'), 'multiple' => TRUE)); } // we need to hide activity tagset for special activities @@ -1011,6 +1008,9 @@ protected function processActivity(&$params) { // add tags if exists $tagParams = array(); if (!empty($params['tag'])) { + if (!is_array($params['tag'])) { + $params['tag'] = explode(',', $params['tag']); + } foreach ($params['tag'] as $tag) { $tagParams[$tag] = 1; } diff --git a/CRM/Admin/Form/Options.php b/CRM/Admin/Form/Options.php index 6c8dad5c5c97..c1f040535676 100644 --- a/CRM/Admin/Form/Options.php +++ b/CRM/Admin/Form/Options.php @@ -134,6 +134,9 @@ public function setDefaultValues() { if ($this->_gName == 'payment_instrument' && $this->_id) { $defaults['financial_account_id'] = CRM_Financial_BAO_FinancialTypeAccount::getFinancialAccount($this->_id, 'civicrm_option_value', 'financial_account_id'); } + if (empty($this->_id) || !CRM_Core_DAO::getFieldValue('CRM_Core_DAO_OptionValue', $this->_id, 'color')) { + $defaults['color'] = '#ffffff'; + } return $defaults; } @@ -174,6 +177,10 @@ public function buildQuickForm() { $this->add('text', 'icon', ts('Icon'), array('class' => 'crm-icon-picker', 'title' => ts('Choose Icon'), 'allowClear' => TRUE)); } + if ($this->_gName == 'activity_status') { + $this->add('color', 'color', ts('Color')); + } + if (!in_array($this->_gName, array( 'email_greeting', 'postal_greeting', @@ -428,7 +435,7 @@ public function postProcess() { } } else { - $params = $ids = array(); + $ids = array(); $params = $this->exportValues(); // allow multiple defaults within group. @@ -458,6 +465,10 @@ public function postProcess() { } } + if (isset($params['color']) && strtolower($params['color']) == '#ffffff') { + $params['color'] = 'null'; + } + $groupParams = array('name' => ($this->_gName)); $optionValue = CRM_Core_OptionValue::addOptionValue($params, $groupParams, $this->_action, $this->_id); diff --git a/CRM/Admin/Page/AJAX.php b/CRM/Admin/Page/AJAX.php index 139321abe4f5..4374d62403c4 100644 --- a/CRM/Admin/Page/AJAX.php +++ b/CRM/Admin/Page/AJAX.php @@ -266,7 +266,7 @@ public static function mergeTagList() { // query to list mergable tags $query = " -SELECT t1.name, t1.id, t1.used_for, t2.name as parent +SELECT t1.name, t1.id, t1.used_for, t1.color, t2.name as parent FROM civicrm_tag t1 LEFT JOIN civicrm_tag t2 ON t1.parent_id = t2.id WHERE t1.id <> {$fromId} AND @@ -280,6 +280,7 @@ public static function mergeTagList() { $row = array( 'id' => $dao->id, 'text' => ($dao->parent ? "{$dao->parent} :: " : '') . $dao->name, + 'color' => isset($dao->color) ? $dao->color : NULL, ); // Add warning about used_for types if (!empty($dao->used_for)) { diff --git a/CRM/Case/BAO/Case.php b/CRM/Case/BAO/Case.php index 02db237d8bc4..d887a323ba6f 100644 --- a/CRM/Case/BAO/Case.php +++ b/CRM/Case/BAO/Case.php @@ -1091,7 +1091,7 @@ public static function getCaseActivity($caseID, &$params, $contactID, $context = $caseActivity['DT_RowId'] = $caseActivityId; //Add classes to the row, via DataTables syntax - $caseActivity['DT_RowClass'] = "crm-entity"; + $caseActivity['DT_RowClass'] = "crm-entity status-id-$dao->status"; if (CRM_Utils_Array::crmInArray($dao->status, $compStatusValues)) { $caseActivity['DT_RowClass'] .= " status-completed"; diff --git a/CRM/Case/Form/Case.php b/CRM/Case/Form/Case.php index 76c61baaf54b..f236b23dab0d 100644 --- a/CRM/Case/Form/Case.php +++ b/CRM/Case/Form/Case.php @@ -244,12 +244,11 @@ public function buildQuickForm() { )), TRUE ); - CRM_Core_BAO_Tag::getTags('civicrm_case', $tags, NULL, - ' ', TRUE); + $tags = CRM_Core_BAO_Tag::getColorTags('civicrm_case'); if (!empty($tags)) { - $this->add('select', 'tag', ts('Select Tags'), $tags, FALSE, - array('id' => 'tags', 'multiple' => 'multiple', 'class' => 'crm-select2') + $this->add('select2', 'tag', ts('Tags'), $tags, FALSE, + array('class' => 'huge', 'multiple' => 'multiple') ); } @@ -371,6 +370,9 @@ public function postProcess() { $tagParams = array(); if (!empty($params['tag'])) { $tagParams = array(); + if (!is_array($params['tag'])) { + $params['tag'] = explode(',', $params['tag']); + } foreach ($params['tag'] as $tag) { $tagParams[$tag] = 1; } diff --git a/CRM/Case/Form/CaseView.php b/CRM/Case/Form/CaseView.php index 2eabfc6e5499..ad0de50ff575 100644 --- a/CRM/Case/Form/CaseView.php +++ b/CRM/Case/Form/CaseView.php @@ -343,28 +343,28 @@ public function buildQuickForm() { $this->assign('hookCaseSummary', $hookCaseSummary); } - CRM_Core_BAO_Tag::getTags('civicrm_case', $allTags, NULL, - ' ', TRUE); + $allTags = CRM_Core_BAO_Tag::getColorTags('civicrm_case'); if (!empty($allTags)) { - $this->add('select', 'case_tag', ts('Tags'), $allTags, FALSE, - array('id' => 'tags', 'multiple' => 'multiple', 'class' => 'crm-select2') + $this->add('select2', 'case_tag', ts('Tags'), $allTags, FALSE, + array('id' => 'tags', 'multiple' => 'multiple') ); $tags = CRM_Core_BAO_EntityTag::getTag($this->_caseID, 'civicrm_case'); - $this->setDefaults(array('case_tag' => $tags)); - foreach ($tags as $tid) { - if (isset($allTags[$tid])) { - $tags[$tid] = $allTags[$tid]; + $tagInfo = CRM_Utils_Array::findInTree($tid, $allTags); + if ($tagInfo) { + $tags[$tid] = $tagInfo; } else { unset($tags[$tid]); } } - $this->assign('tags', implode(', ', array_filter($tags))); + $this->setDefaults(array('case_tag' => implode(',', array_keys($tags)))); + + $this->assign('tags', $tags); $this->assign('showTags', TRUE); } else { diff --git a/CRM/Contact/Page/View/Summary.php b/CRM/Contact/Page/View/Summary.php index 02fe9db092c2..ae7c9be46458 100644 --- a/CRM/Contact/Page/View/Summary.php +++ b/CRM/Contact/Page/View/Summary.php @@ -220,7 +220,8 @@ public function view() { $contactTags = CRM_Core_BAO_EntityTag::getContactTags($this->_contactId); if (!empty($contactTags)) { - $defaults['contactTag'] = implode(', ', $contactTags); + $defaults['contactTag'] = $contactTags; + $defaults['allTags'] = CRM_Core_BAO_Tag::getTagsUsedFor('civicrm_contact', FALSE); } $defaults['privacy_values'] = CRM_Core_SelectValues::privacy(); diff --git a/CRM/Core/BAO/Tag.php b/CRM/Core/BAO/Tag.php index e22af2bfce8c..7b158f8e34a2 100644 --- a/CRM/Core/BAO/Tag.php +++ b/CRM/Core/BAO/Tag.php @@ -172,6 +172,7 @@ public static function getTagsUsedFor( $tags[$tag->id]['parent_id'] = $tag->parent_id; $tags[$tag->id]['is_tagset'] = $tag->is_tagset; $tags[$tag->id]['used_for'] = $tag->used_for; + $tags[$tag->id]['color'] = !empty($tag->color) ? $tag->color : NULL; } } $tag->free(); @@ -313,6 +314,42 @@ public static function getTags( return $tags; } + /** + * @param string $usedFor + * @param bool $allowSelectingNonSelectable + * @param null $exclude + * @return array + * @throws \CiviCRM_API3_Exception + */ + public static function getColorTags($usedFor = NULL, $allowSelectingNonSelectable = FALSE, $exclude = NULL) { + $params = array( + 'options' => array('limit' => 0), + 'is_tagset' => 0, + 'return' => array('name', 'description', 'parent_id', 'color', 'is_selectable', 'used_for'), + ); + if ($usedFor) { + $params['used_for'] = array('LIKE' => "%$usedFor%"); + } + if ($exclude) { + $params['id'] = array('!=' => $exclude); + } + $allTags = array(); + foreach (CRM_Utils_Array::value('values', civicrm_api3('Tag', 'get', $params)) as $id => $tag) { + $allTags[$id] = array( + 'text' => $tag['name'], + 'id' => $id, + 'description' => CRM_Utils_Array::value('description', $tag), + 'parent_id' => CRM_Utils_Array::value('parent_id', $tag), + 'used_for' => CRM_Utils_Array::value('used_for', $tag), + 'color' => CRM_Utils_Array::value('color', $tag), + ); + if (!$allowSelectingNonSelectable && empty($tag['is_selectable'])) { + $allTags[$id]['disabled'] = TRUE; + } + } + return CRM_Utils_Array::buildTree($allTags); + } + /** * Delete the tag. * @@ -345,7 +382,7 @@ public static function del($id) { } /** - * Takes an associative array and creates a contact object. + * Takes an associative array and creates a tag object. * * The function extract all the params it needs to initialize the create a * contact object. the params array could contain additional unused name/value diff --git a/CRM/Core/DAO/OptionValue.php b/CRM/Core/DAO/OptionValue.php index 00fdf022bd24..8a27e6203a17 100644 --- a/CRM/Core/DAO/OptionValue.php +++ b/CRM/Core/DAO/OptionValue.php @@ -30,7 +30,7 @@ * * Generated from xml/schema/CRM/Core/OptionValue.xml * DO NOT EDIT. Generated by CRM_Core_CodeGen - * (GenCodeChecksum:7581126bad606520292d883da2f620ca) + * (GenCodeChecksum:fdf2f62ba69b54da0567362493827448) */ require_once 'CRM/Core/DAO.php'; require_once 'CRM/Utils/Type.php'; @@ -149,6 +149,12 @@ class CRM_Core_DAO_OptionValue extends CRM_Core_DAO { * @var string */ public $icon; + /** + * Hex color value e.g. #ffffff + * + * @var string + */ + public $color; /** * class constructor * @@ -335,6 +341,15 @@ static function &fields() { 'size' => CRM_Utils_Type::HUGE, 'default' => 'NULL', ) , + 'color' => array( + 'name' => 'color', + 'type' => CRM_Utils_Type::T_STRING, + 'title' => ts('Color') , + 'description' => 'Hex color value e.g. #ffffff', + 'maxlength' => 255, + 'size' => CRM_Utils_Type::HUGE, + 'default' => 'NULL', + ) , ); CRM_Core_DAO_AllCoreTables::invoke(__CLASS__, 'fields_callback', Civi::$statics[__CLASS__]['fields']); } diff --git a/CRM/Core/DAO/Tag.php b/CRM/Core/DAO/Tag.php index 75835d6dabf5..f412f0cbcf26 100644 --- a/CRM/Core/DAO/Tag.php +++ b/CRM/Core/DAO/Tag.php @@ -30,7 +30,7 @@ * * Generated from xml/schema/CRM/Core/Tag.xml * DO NOT EDIT. Generated by CRM_Core_CodeGen - * (GenCodeChecksum:e62b7ed2ffb1714200328dd2b08cdc9c) + * (GenCodeChecksum:1e6ad1d5a7c05b1a7d300d2a7722ba4d) */ require_once 'CRM/Core/DAO.php'; require_once 'CRM/Utils/Type.php'; @@ -99,6 +99,12 @@ class CRM_Core_DAO_Tag extends CRM_Core_DAO { * @var int unsigned */ public $created_id; + /** + * Hex color value e.g. #ffffff + * + * @var string + */ + public $color; /** * Date and time that tag was created. * @@ -208,6 +214,15 @@ static function &fields() { 'description' => 'FK to civicrm_contact, who created this tag', 'FKClassName' => 'CRM_Contact_DAO_Contact', ) , + 'color' => array( + 'name' => 'color', + 'type' => CRM_Utils_Type::T_STRING, + 'title' => ts('Color') , + 'description' => 'Hex color value e.g. #ffffff', + 'maxlength' => 255, + 'size' => CRM_Utils_Type::HUGE, + 'default' => 'NULL', + ) , 'created_date' => array( 'name' => 'created_date', 'type' => CRM_Utils_Type::T_DATE + CRM_Utils_Type::T_TIME, diff --git a/CRM/Core/Form.php b/CRM/Core/Form.php index c694a8525234..e01cbb70edb3 100644 --- a/CRM/Core/Form.php +++ b/CRM/Core/Form.php @@ -217,6 +217,7 @@ class CRM_Core_Form extends HTML_QuickForm_Page { 'number', 'url', 'email', + 'color', ); /** @@ -345,6 +346,7 @@ public function &add( $attributes = '', $required = FALSE, $extra = NULL ) { // Fudge some extra types that quickform doesn't support + $inputType = $type; if ($type == 'wysiwyg' || in_array($type, self::$html5Types)) { $attributes = ($attributes ? $attributes : array()) + array('class' => ''); $attributes['class'] = ltrim($attributes['class'] . " crm-form-$type"); @@ -354,6 +356,16 @@ public function &add( } $type = $type == 'wysiwyg' ? 'textarea' : 'text'; } + // Like select but accepts rich array data (with nesting, colors, icons, etc) as option list. + if ($inputType == 'select2') { + $type = 'text'; + $options = $attributes; + $attributes = $attributes = ($extra ? $extra : array()) + array('class' => ''); + $attributes['class'] = ltrim($attributes['class'] . " crm-select2 crm-form-select2"); + $attributes['data-select-params'] = json_encode(array('data' => $options, 'multiple' => !empty($attributes['multiple']))); + unset($attributes['multiple']); + $extra = NULL; + } // @see http://wiki.civicrm.org/confluence/display/CRMDOC/crmDatepicker if ($type == 'datepicker') { $attributes = ($attributes ? $attributes : array()); @@ -384,6 +396,10 @@ public function &add( CRM_Core_Error::fatal(HTML_QuickForm::errorMessage($element)); } + if ($inputType == 'color') { + $this->addRule($name, ts('%1 must contain a color value e.g. #ffffff.', array(1 => $label)), 'regex', '/#[0-9a-fA-F]{6}/'); + } + if ($required) { if ($type == 'file') { $error = $this->addRule($name, ts('%1 is a required field.', array(1 => $label)), 'uploadedfile'); diff --git a/CRM/Core/Form/Renderer.php b/CRM/Core/Form/Renderer.php index 6f235382dbf9..3eeb16091dff 100644 --- a/CRM/Core/Form/Renderer.php +++ b/CRM/Core/Form/Renderer.php @@ -120,6 +120,9 @@ public function _elementToArray(&$element, $required, $error) { if ($element->getAttribute('data-api-entity') && $element->getAttribute('data-entity-value')) { $this->renderFrozenEntityRef($el, $element); } + elseif ($element->getAttribute('type') == 'text' && $element->getAttribute('data-select-params')) { + $this->renderFrozenSelect2($el, $element); + } elseif ($element->getAttribute('type') == 'text' && $element->getAttribute('formatType')) { list($date, $time) = CRM_Utils_Date::setDateDefaults($element->getValue(), $element->getAttribute('formatType'), $element->getAttribute('format'), $element->getAttribute('timeformat')); $date .= ($element->getAttribute('timeformat')) ? " $time" : ''; @@ -253,6 +256,27 @@ public static function preProcessEntityRef($field) { $field->setValue(implode(',', $val)); } + /** + * Render select2 as text. + * + * @param array $el + * @param HTML_QuickForm_element $field + */ + public function renderFrozenSelect2(&$el, $field) { + $params = json_decode($field->getAttribute('data-select-params'), TRUE); + $val = $field->getValue(); + if ($val && !empty($params['data'])) { + $display = array(); + foreach (explode(',', $val) as $item) { + $match = CRM_Utils_Array::findInTree($item, $params['data']); + if (isset($match['text']) && strlen($match['text'])) { + $display[] = $match['text']; + } + } + $el['html'] = implode('; ', $display) . ''; + } + } + /** * Render entity references as text. * If user has permission, format as link (for now limited to contacts). diff --git a/CRM/Core/Smarty/plugins/modifier.colorContrast.php b/CRM/Core/Smarty/plugins/modifier.colorContrast.php new file mode 100644 index 000000000000..b1145e193de0 --- /dev/null +++ b/CRM/Core/Smarty/plugins/modifier.colorContrast.php @@ -0,0 +1,45 @@ +setPageTitle($this->_isTagSet ? ts('Tag Set') : ts('Tag')); - if ($this->_action == CRM_Core_Action::DELETE) { if ($this->_id && $tag = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'name', 'parent_id')) { $url = CRM_Utils_System::url('civicrm/tag', "reset=1"); @@ -60,6 +58,9 @@ public function buildQuickForm() { } } else { + $parentId = NULL; + $isTagsetChild = FALSE; + $this->_isTagSet = CRM_Utils_Request::retrieve('tagset', 'Positive', $this); if (!$this->_isTagSet && @@ -69,14 +70,16 @@ public function buildQuickForm() { $this->_isTagSet = TRUE; } - $allTag = array('' => ts('- select -')) + CRM_Core_BAO_Tag::getTagsNotInTagset(); - if ($this->_id) { - unset($allTag[$this->_id]); + $parentId = CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'parent_id'); + $isTagSetChild = $parentId ? CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $parentId, 'is_tagset') : FALSE; } if (!$this->_isTagSet) { - $this->add('select', 'parent_id', ts('Parent Tag'), $allTag, FALSE, array('class' => 'crm-select2')); + if (!$isTagSetChild) { + $colorTags = CRM_Core_BAO_Tag::getColorTags(NULL, TRUE, $this->_id); + $this->add('select2', 'parent_id', ts('Parent Tag'), $colorTags, FALSE, array('placeholder' => ts('- select -'))); + } // Tagsets are not selectable by definition so only include the selectable field if NOT a tagset. $selectable = $this->add('checkbox', 'is_selectable', ts('Selectable?')); @@ -85,6 +88,7 @@ public function buildQuickForm() { $selectable->setValue(1); } + $this->add('color', 'color', ts('Color')); } $this->assign('isTagSet', $this->_isTagSet); @@ -105,13 +109,7 @@ public function buildQuickForm() { $isReserved = $this->add('checkbox', 'is_reserved', ts('Reserved?')); - $usedFor = $this->addSelect('used_for', array('multiple' => TRUE, 'option_url' => NULL)); - - if ($this->_id && - CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'parent_id') - ) { - $usedFor->freeze(); - } + $this->addSelect('used_for', array('multiple' => TRUE, 'option_url' => NULL)); $adminTagset = TRUE; if (!CRM_Core_Permission::check('administer Tagsets')) { @@ -125,21 +123,32 @@ public function buildQuickForm() { $adminReservedTags = FALSE; } $this->assign('adminReservedTags', $adminReservedTags); - } + $this->setPageTitle($this->_isTagSet ? ts('Tag Set') : ts('Tag')); parent::buildQuickForm(); } + public function setDefaultValues() { + $defaults = parent::setDefaultValues(); + if (empty($this->_id) || !CRM_Core_DAO::getFieldValue('CRM_Core_DAO_Tag', $this->_id, 'color')) { + $defaults['color'] = '#ffffff'; + } + if (empty($this->_id)) { + $defaults['used_for'] = 'civicrm_contact'; + } + return $defaults; + } + /** * Process the form submission. */ public function postProcess() { - $params = $ids = array(); - // store the submitted values in an array $params = $this->exportValues(); + if ($this->_id) { + $params['id'] = $this->_id; + } - $ids['tag'] = $this->_id; if ($this->_action == CRM_Core_Action::ADD || $this->_action == CRM_Core_Action::UPDATE ) { @@ -159,16 +168,20 @@ public function postProcess() { $params['is_selectable'] = 0; } + if (strtolower($params['color']) == '#ffffff') { + $params['color'] = 'null'; + } + if ($this->_action == CRM_Core_Action::DELETE) { if ($this->_id > 0) { $tag = civicrm_api3('tag', 'getsingle', array('id' => $this->_id)); CRM_Core_BAO_Tag::del($this->_id); - CRM_Core_Session::setStatus(ts('The tag \'%1\' has been deleted.', array(1 => $tag['name'])), ts('Deleted'), 'success'); + CRM_Core_Session::setStatus(ts("The tag '%1' has been deleted.", array(1 => $tag['name'])), ts('Deleted'), 'success'); } } else { - $tag = CRM_Core_BAO_Tag::add($params, $ids); - CRM_Core_Session::setStatus(ts('The tag \'%1\' has been saved.', array(1 => $tag->name)), ts('Saved'), 'success'); + $tag = CRM_Core_BAO_Tag::add($params); + CRM_Core_Session::setStatus(ts("The tag '%1' has been saved.", array(1 => $tag->name)), ts('Saved'), 'success'); } } diff --git a/CRM/Tag/Form/Tag.php b/CRM/Tag/Form/Tag.php index a786ebe19ff9..7809b1f871eb 100644 --- a/CRM/Tag/Form/Tag.php +++ b/CRM/Tag/Form/Tag.php @@ -76,10 +76,10 @@ public function buildQuickForm() { $this->assign('tagged', $entityTag); // get the list of all the categories - $allTag = CRM_Core_BAO_Tag::getTagsUsedFor($this->_entityTable); + $allTags = CRM_Core_BAO_Tag::getTagsUsedFor($this->_entityTable, FALSE); // need to append the array with the " checked " if contact is tagged with the tag - foreach ($allTag as $tagID => $varValue) { + foreach ($allTags as $tagID => $varValue) { if (in_array($tagID, $entityTag)) { $tagAttribute = array( 'checked' => 'checked', @@ -112,7 +112,7 @@ public function buildQuickForm() { } $this->assign('tree', $tree); - $this->assign('tag', $allTag); + $this->assign('allTags', $allTags); //build tag widget $parentNames = CRM_Core_BAO_Tag::getTagSet('civicrm_contact'); diff --git a/CRM/Tag/Page/Tag.php b/CRM/Tag/Page/Tag.php index 20ed8e097e95..42327a960bcd 100644 --- a/CRM/Tag/Page/Tag.php +++ b/CRM/Tag/Page/Tag.php @@ -164,10 +164,12 @@ public function browse($action = NULL, $sort = NULL) { $usedFor = CRM_Core_OptionGroup::values('tag_used_for'); - $query = "SELECT t1.name, t1.id, t2.name as parent, t1.description, t1.used_for, t1.is_tagset, - t1.is_reserved, t1.parent_id, t1.used_for - FROM civicrm_tag t1 LEFT JOIN civicrm_tag t2 ON t1.parent_id = t2.id - GROUP BY t1.parent_id, t1.id"; + $query = " SELECT t1.name, t1.id, t2.name as parent, t1.description, t1.used_for, t1.is_tagset as is_tagset, + t1.is_reserved, t1.parent_id, t1.used_for, t1.color, t2.is_tagset as is_tagset_child, t2.parent_id as grandparent_id + FROM civicrm_tag t1 + LEFT JOIN civicrm_tag t2 ON t1.parent_id = t2.id + LEFT JOIN civicrm_tag t3 ON t2.parent_id = t3.id + ORDER BY CONCAT(IFNULL(t3.name, ''), IFNULL(t2.name, ''), t1.name)"; $tag = CRM_Core_DAO::executeQuery($query); $values = array(); @@ -186,9 +188,7 @@ public function browse($action = NULL, $sort = NULL) { } } - if (!empty($used)) { - $values[$tag->id]['used_for'] = implode(", ", $used); - } + $values[$tag->id]['used_for'] = implode(", ", $used); $newAction = $action; if ($values[$tag->id]['is_reserved']) { diff --git a/CRM/Upgrade/Incremental/php/FourSeven.php b/CRM/Upgrade/Incremental/php/FourSeven.php index e51dee5950a5..a1e54cfd3d9b 100644 --- a/CRM/Upgrade/Incremental/php/FourSeven.php +++ b/CRM/Upgrade/Incremental/php/FourSeven.php @@ -284,6 +284,10 @@ public function upgrade_4_7_15($rev) { 'civicrm_option_value', 'icon', "varchar(255) COMMENT 'crm-i icon class' DEFAULT NULL"); $this->addTask('CRM-19626 - Add min_amount column to civicrm_price_set', 'addColumn', 'civicrm_price_set', 'min_amount', "INT(10) UNSIGNED DEFAULT '0' COMMENT 'Minimum Amount required for this set.'"); + $this->addTask('CRM-19769 - Add color column to civicrm_tag', 'addColumn', + 'civicrm_tag', 'color', "varchar(255) COMMENT 'Hex color value e.g. #ffffff' DEFAULT NULL"); + $this->addTask('CRM-19779 - Add color column to civicrm_option_value', 'addColumn', + 'civicrm_option_value', 'color', "varchar(255) COMMENT 'Hex color value e.g. #ffffff' DEFAULT NULL"); $this->addTask(ts('Upgrade DB to %1: SQL', array(1 => $rev)), 'runSql', $rev); } diff --git a/CRM/Utils/Array.php b/CRM/Utils/Array.php index d82250cc7460..c2862e3449a7 100644 --- a/CRM/Utils/Array.php +++ b/CRM/Utils/Array.php @@ -1098,4 +1098,35 @@ public static function encode_items($array) { return $array; } + public static function buildTree($elements, $parentId = NULL) { + $branch = array(); + + foreach ($elements as $element) { + if ($element['parent_id'] == $parentId) { + $children = self::buildTree($elements, $element['id']); + if ($children) { + $element['children'] = $children; + } + $branch[] = $element; + } + } + + return $branch; + } + + public static function findInTree($search, $tree, $field = 'id') { + foreach ($tree as $item) { + if ($item[$field] == $search) { + return $item; + } + if (!empty($item['children'])) { + $found = self::findInTree($search, $item['children']); + if ($found) { + return $found; + } + } + } + return NULL; + } + } diff --git a/CRM/Utils/Color.php b/CRM/Utils/Color.php new file mode 100644 index 000000000000..6349f8b7a551 --- /dev/null +++ b/CRM/Utils/Color.php @@ -0,0 +1,56 @@ += 128) ? 'black' : 'white'; + } + +} diff --git a/api/v3/Generic/Getlist.php b/api/v3/Generic/Getlist.php index b9334989ce69..1d4cac1dc0cd 100644 --- a/api/v3/Generic/Getlist.php +++ b/api/v3/Generic/Getlist.php @@ -88,6 +88,7 @@ function _civicrm_api3_generic_getList_defaults($entity, &$request, $apiDefaults 'page_num' => 1, 'input' => '', 'image_field' => NULL, + 'color_field' => isset($fields['color']) ? 'color' : NULL, 'id_field' => $entity == 'option_value' ? 'value' : 'id', 'description_field' => array(), 'params' => array(), @@ -149,6 +150,9 @@ function _civicrm_api3_generic_getlist_params(&$request) { if (!empty($request['image_field'])) { $fieldsToReturn[] = $request['image_field']; } + if (!empty($request['color_field'])) { + $fieldsToReturn[] = $request['color_field']; + } if (!empty($request['description_field'])) { $fieldsToReturn = array_merge($fieldsToReturn, (array) $request['description_field']); } @@ -193,6 +197,9 @@ function _civicrm_api3_generic_getlist_output($result, $request, $entity, $field if (!empty($request['image_field'])) { $data['image'] = isset($row[$request['image_field']]) ? $row[$request['image_field']] : ''; } + if (isset($row[$request['color_field']])) { + $data['color'] = $row[$request['color_field']]; + } $output[] = $data; } } diff --git a/css/civicrm.css b/css/civicrm.css index 90d6ffb3812d..716350ba6c0a 100644 --- a/css/civicrm.css +++ b/css/civicrm.css @@ -3054,14 +3054,14 @@ div.m ul#civicrm-menu, } .crm-container .select2-results li, .crm-container .select2-results .crm-select2-row, -.crm-container .select2-results .crm-select2-row .crm-select2-row-description p { +.crm-container .select2-results .crm-select2-row-description p { padding: 0; margin: 0; } .crm-container .select2-results .crm-select2-row .crm-select2-row-label { font-size: 1.1em; } -.crm-container .select2-results .crm-select2-row .crm-select2-row-description p { +.crm-container .select2-results .crm-select2-row-description p { font-size: 0.8em; line-height: 1.5em; color: #696969; @@ -3069,10 +3069,14 @@ div.m ul#civicrm-menu, white-space: nowrap; overflow: hidden; text-overflow: ellipsis; + font-weight: normal; } -.crm-container .select2-results .select2-highlighted .crm-select2-row .crm-select2-row-description p { +.crm-container .select2-results .select2-highlighted > .select2-result-label .crm-select2-row-description p { color: #f0f0f0; } +.select2-container .crm-select2-row-description { + display: none; +} .crm-container .select2-results .crm-select2-icon { width: 20px; height: 100%; @@ -3104,6 +3108,14 @@ div.m ul#civicrm-menu, box-sizing: border-box; } +span.crm-select-item-color { + display: inline-block; + width: .8em; + height: .7em; + border-radius: 2px; + border: 1px solid grey; +} + /* jQuery UI styles */ .crm-container .ui-progressbar-value { background-image: url("../packages/jquery/css/images/pbar-ani.gif"); @@ -3811,3 +3823,10 @@ span.crm-status-icon { .crm-container .crm-grip { cursor: move; } + +.crm-tag-item { + display: inline-block; + padding: 1px 5px; + border-radius: 3px; + border: 1px solid grey; +} \ No newline at end of file diff --git a/css/contactSummary.css b/css/contactSummary.css index 0c248d78bfde..a0b14924a98e 100644 --- a/css/contactSummary.css +++ b/css/contactSummary.css @@ -350,4 +350,4 @@ div#crm-contact-thumbnail { } #tagGroup table { color: #000; -} \ No newline at end of file +} diff --git a/js/Common.js b/js/Common.js index 38a2a20939d5..346e926f262b 100644 --- a/js/Common.js +++ b/js/Common.js @@ -373,8 +373,17 @@ if (!CRM.vars) CRM.vars = {}; }; function formatCrmSelect2(row) { - var icon = $(row.element).data('icon'); - return (icon ? ' ' : '') + _.escape(row.text); + var icon = row.icon || $(row.element).data('icon'), + color = row.color || $(row.element).data('color'), + description = row.description || $(row.element).data('description'), + ret = ''; + if (icon) { + ret += ' '; + } + if (color) { + ret += ' '; + } + return ret + _.escape(row.text) + (description ? '
' + _.escape(description) + '