Sfoglia il codice sorgente

Ticket #5425 - Tasks: Functionality improvements. Stage 2.

AntonLV 6 mesi fa
parent
commit
1d0e61c923

+ 6 - 1
inc/classes/BxDolForm.php

@@ -1583,7 +1583,7 @@ class BxDolFormChecker
             $aValsToUpdate[$sKey] = $valClean;
             $aInputs[$k]['db']['value'] = $valClean;
 
-            if (null !== $aTrackTextFieldsChanges && isset(BxDolForm::$TYPES_TEXT[$aInputs[$k]['type']]) && isset($aTrackTextFieldsChanges['data'][$a['name']]) && $aTrackTextFieldsChanges['data'][$a['name']] != $valClean)
+            if (null !== $aTrackTextFieldsChanges && $this->isTrackableField($a) && isset($aTrackTextFieldsChanges['data'][$a['name']]) && $aTrackTextFieldsChanges['data'][$a['name']] != $valClean)
                 $aTrackTextFieldsChanges['changed_fields'][] = $a['name'];
         }
 
@@ -1663,6 +1663,11 @@ class BxDolFormChecker
             }
         }
     }
+
+    function isTrackableField($aInput)
+    {
+        return isset(BxDolForm::$TYPES_TEXT[$aInput['type']]);
+    }
 }
 
 class BxDolFormCheckerHelper

+ 35 - 3
modules/boonex/russian/data/langs/bx_tasks/ru.xml

@@ -41,6 +41,8 @@
     <string name="_bx_tasks_form_entry_input_sys_title"><![CDATA[Заголовок]]></string>
     <string name="_bx_tasks_form_entry_input_title"><![CDATA[Заголовок]]></string>
     <string name="_bx_tasks_form_entry_input_title_err"><![CDATA[Заголовок обязателен. Пожалуйста, заполните это поле]]></string>
+    <string name="_bx_tasks_form_entry_input_sys_stickers"><![CDATA[Метки]]></string>
+    <string name="_bx_tasks_form_entry_input_stickers"><![CDATA[Метки]]></string>
     <string name="_bx_tasks_form_entry_input_sys_type"><![CDATA[Тип]]></string>
     <string name="_bx_tasks_form_entry_input_type"><![CDATA[Тип]]></string>
     <string name="_bx_tasks_form_entry_input_sys_priority"><![CDATA[Приоритет]]></string>
@@ -143,6 +145,15 @@
     <string name="_bx_tasks_popup_title_time_add"><![CDATA[Добавить время]]></string>
     <string name="_bx_tasks_popup_title_time_edit"><![CDATA[Редактировать время]]></string>
 
+    <string name="_bx_tasks_form_pv_input_title"><![CDATA[Заголовок]]></string>
+    <string name="_bx_tasks_form_pv_input_color"><![CDATA[Цвет]]></string>
+    <string name="_bx_tasks_form_pv_input_color_inf"><![CDATA[Используйте цветовую кодировку RGB.]]></string>
+    <string name="_bx_tasks_form_pv_input_submit"><![CDATA[Выполнить]]></string>
+    <string name="_bx_tasks_form_pv_input_cancel"><![CDATA[Отменить]]></string>
+    <string name="_bx_tasks_form_pv_input_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_tasks_popup_pv_title_add"><![CDATA[Добавить значение]]></string>
+    <string name="_bx_tasks_popup_pv_title_edit"><![CDATA[Редактировать значение]]></string>
+
     <string name="_bx_tasks_category_form_entry"><![CDATA[Форма Категории]]></string>
     <string name="_bx_tasks_category_display_add"><![CDATA[Добавить категорию]]></string>
     <string name="_bx_tasks_category_display_edit"><![CDATA[Редактировать категорию]]></string>
@@ -275,6 +286,10 @@
     <string name="_bx_tasks_page_block_title_entries_time_in_context"><![CDATA[Мое время в <a href="{profile_link}">{display_name}</a>]]></string>
     <string name="_bx_tasks_page_block_title_sys_entries_time_in_context_administration"><![CDATA[Всё время в контексте]]></string>
     <string name="_bx_tasks_page_block_title_entries_time_in_context_administration"><![CDATA[Всё время в <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_tasks_page_title_sys_context_pre_values"><![CDATA[Списки и значения в контексте]]></string>
+    <string name="_bx_tasks_page_title_context_pre_values"><![CDATA[Списки и значения]]></string>
+    <string name="_bx_tasks_page_block_title_system_context_pre_values"><![CDATA[Списки и значения]]></string>
+    <string name="_bx_tasks_page_block_title_context_pre_values"><![CDATA[Списки и значения]]></string>
     <string name="_bx_tasks_page_block_title_system_menu_browse"><![CDATA[Меню просмотра]]></string>
     <string name="_bx_tasks_page_block_title_menu_browse"><![CDATA[Просмотр задач]]></string>
 
@@ -352,6 +367,12 @@
     <string name="_bx_tasks_menu_item_title_view_context_time"><![CDATA[Моё время]]></string>
     <string name="_bx_tasks_menu_item_title_system_view_context_time_administration"><![CDATA[Всё время]]></string>
     <string name="_bx_tasks_menu_item_title_view_context_time_administration"><![CDATA[Всё время]]></string>
+    <string name="_bx_tasks_menu_title_manage_context_submenu"><![CDATA[Управление контекстом - Подменю]]></string>
+    <string name="_bx_tasks_menu_set_title_manage_context_submenu"><![CDATA[Управление контекстом - Подменю]]></string>
+    <string name="_bx_tasks_menu_item_title_system_manage_context_pre_values"><![CDATA[Списки и значения]]></string>
+    <string name="_bx_tasks_menu_item_title_manage_context_pre_values"><![CDATA[Списки и значения]]></string>
+    <string name="_bx_tasks_menu_item_title_system_manage_context_settings"><![CDATA[Настройки]]></string>
+    <string name="_bx_tasks_menu_item_title_manage_context_settings"><![CDATA[Настройки]]></string>
     <string name="_bx_tasks_menu_title_manage_tools_submenu"><![CDATA[Инструменты управления - Подменю]]></string>
     <string name="_bx_tasks_menu_set_title_manage_tools_submenu"><![CDATA[Инструменты управления - Подменю]]></string>
     <string name="_bx_tasks_menu_item_title_mt_submenu_entries_common"><![CDATA[Мои задания]]></string>
@@ -398,6 +419,13 @@
     <string name="_bx_tasks_grid_filter_item_title_tm_select_one_context_module"><![CDATA[Любой модуль]]></string>
     <string name="_bx_tasks_grid_filter_item_title_tm_select_one_object_id"><![CDATA[Любая задача]]></string>
 
+    <string name="_bx_tasks_grid_column_title_pv_title"><![CDATA[Заголовок]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_add"><![CDATA[Добавить]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_edit"><![CDATA[Редактировать]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_delete"><![CDATA[Удалить]]></string>
+    <string name="_bx_tasks_grid_filter_item_title_pv_select_one_list"><![CDATA[Выберите список...]]></string>
+
+    <!-- Charts -->
     <string name="_bx_tasks_chart_growth"><![CDATA[Tasks: Growth]]></string>
     <string name="_bx_tasks_chart_growth_speed"><![CDATA[Tasks: Growth Speed]]></string>
 
@@ -416,6 +444,12 @@
     <string name="_bx_tasks_type_1"><![CDATA[Ошибка]]></string>
     <string name="_bx_tasks_type_2"><![CDATA[Свойство]]></string>
     <string name="_bx_tasks_type_3"><![CDATA[Задача]]></string>
+    <string name="_bx_tasks_pre_lists_stickers"><![CDATA[Метки]]></string>
+    <string name="_bx_tasks_sticker_1"><![CDATA[Ошибка]]></string>
+    <string name="_bx_tasks_sticker_2"><![CDATA[Свойство]]></string>
+    <string name="_bx_tasks_sticker_3"><![CDATA[Улучшение]]></string>
+    <string name="_bx_tasks_sticker_4"><![CDATA[Исследование]]></string>
+    <string name="_bx_tasks_sticker_5"><![CDATA[Обсуждение]]></string>
     <string name="_bx_tasks_pre_lists_priorities"><![CDATA[Приоритеты]]></string>
     <string name="_bx_tasks_priority_1"><![CDATA[Срочный]]></string>
     <string name="_bx_tasks_priority_2"><![CDATA[Высокий]]></string>
@@ -489,7 +523,6 @@
     <string name="_bx_tasks_txt_processing_failed"><![CDATA[Задание не была опубликовано, тк произошла ошибка при конвертации видео. Обновите видео, чтобы решить проблему.]]></string>
     <string name="_bx_tasks_txt_scheduled_awaiting"><![CDATA[Дата публикации:  {date_publish_uf}]]></string>
     <string name="_bx_tasks_txt_new_task_list"><![CDATA[Новый список заданий]]></string>
-    <string name="_bx_tasks_txt_new_settings"><![CDATA[Настройки]]></string>
     <string name="_bx_tasks_txt_new_task"><![CDATA[Новое Задание]]></string>
     <string name="_bx_tasks_txt_total"><![CDATA[Потрачено времени: {0}]]></string>
     <string name="_bx_tasks_txt_estimate"><![CDATA[Выделено времени: {0}]]></string>
@@ -502,11 +535,10 @@
     <string name="_bx_tasks_txt_timer_log"><![CDATA[Внести]]></string>
 
     <string name="_bx_tasks_txt_err_cannot_perform_action"><![CDATA[Невозможно выполнить действие. Пожалуйста, оповестите нас об этой проблеме.]]></string>
-    <string name="_bx_tasks_txt_err_cannot_perform_action"><![CDATA[Невозможно выполнить действие. Пожалуйста, оповестите нас об этой проблеме.]]></string>
+    <string name="_bx_tasks_txt_err_empty_pre_list"><![CDATA[Пожалуйста, выберите список, в который хотите добавить элементы.]]></string>
     <string name="_bx_tasks_txt_msg_status_hidden"><![CDATA[Данное задание было скрыто.]]></string>
     <string name="_bx_tasks_txt_msg_status_pending"><![CDATA[Данное задание ожидает утверждения.]]></string>
     <string name="_bx_tasks_txt_msg_confirm_tasklist_deletion"><![CDATA[Вы удалите все задания, которые содержатся в этом списке заданий. Вы уверены?]]></string>
-
     <string name="_bx_tasks_txt_msg_format"><![CDATA[{0} &#183; <span>{1}</span>]]></string>
     <string name="_bx_tasks_txt_msg_synced"><![CDATA[Задача была синхронизирована с GitHub: <b><a href="{ghi_link}" target="_blank">#{ghi_number}</a></b>]]></string>
     <string name="_bx_tasks_txt_msg_edit_type"><![CDATA[<a href="{author_link}">{author_name}</a> изменил тип на <b>{value}</b>]]></string>

+ 11 - 3
modules/boonex/tasks/classes/BxTasksConfig.php

@@ -40,6 +40,8 @@ class BxTasksConfig extends BxBaseModTextConfig
             'TABLE_TIME' => $aModule['db_prefix'] . 'time',
             'TABLE_TIME_TRACK' => $aModule['db_prefix'] . 'time_track',
             'TABLE_TIMERS' => $aModule['db_prefix'] . 'timers',
+            'TABLE_PRE_LISTS' => $aModule['db_prefix'] . 'pre_lists',
+            'TABLE_PRE_VALUES' => $aModule['db_prefix'] . 'pre_values',
             'TABLE_POLLS' => '',
             'TABLE_ENTRIES_FULLTEXT' => 'title_text',
 
@@ -52,6 +54,7 @@ class BxTasksConfig extends BxBaseModTextConfig
             'FIELD_TITLE' => 'title',
             'FIELD_TEXT' => 'text',
             'FIELD_TEXT_ID' => 'post-text',
+            'FIELD_STICKERS' => 'stickers',
             'FIELD_TYPE' => 'type',
             'FIELD_PRIORITY' => 'priority',
             'FIELD_ESTIMATE' => 'estimate',
@@ -179,11 +182,12 @@ class BxTasksConfig extends BxBaseModTextConfig
             'OBJECT_GRID_TIME_COMMON' => 'bx_tasks_time_common',
             'OBJECT_GRID_TIME_CONTEXT_ADMINISTRATION' => 'bx_tasks_time_context_administration',
             'OBJECT_GRID_TIME_CONTEXT_COMMON' => 'bx_tasks_time_context_common',
-            'OBJECT_GRID_CATEGORIES' => 'bx_tasks_categories',
+            'OBJECT_GRID_PRE_VALUES' => 'bx_tasks_pre_values',
             'OBJECT_UPLOADERS' => array('bx_tasks_simple', 'bx_tasks_html5'),
             'OBJECT_CONTENT_INFO' => 'bx_tasks',
             'OBJECT_CMTS_CONTENT_INFO' => 'bx_tasks_cmts',
             'OBJECT_PRE_LIST_TYPES' => 'bx_tasks_types',
+            'OBJECT_PRE_LIST_STICKERS' => 'bx_tasks_stickers',
             'OBJECT_PRE_LIST_PRIORITIES' => 'bx_tasks_priorities',
             'OBJECT_PRE_LIST_STATES' => 'bx_tasks_states',
             
@@ -257,7 +261,8 @@ class BxTasksConfig extends BxBaseModTextConfig
             'categories' => 'BxDolCategories',
             'tasks' => 'BxTasksView',
             'time' => 'BxTasksTime',
-            'timer' => 'BxTasksTimer'
+            'timer' => 'BxTasksTimer',
+            'pre_values' => 'BxTasksPreValues',
         ]);
 
         $this->_aJsObjects = array_merge($this->_aJsObjects, [
@@ -265,7 +270,8 @@ class BxTasksConfig extends BxBaseModTextConfig
             'categories' => 'oBxDolCategories',
             'tasks' => 'oBxTasksView',
             'time' => 'oBxTasksTime',
-            'timer' => 'oBxTasksTimer'
+            'timer' => 'oBxTasksTimer',
+            'pre_values' => 'oBxTasksPreValues',
         ]);
 
         $this->_aGridObjects = [
@@ -275,6 +281,7 @@ class BxTasksConfig extends BxBaseModTextConfig
             'time_administration' => $this->CNF['OBJECT_GRID_TIME_ADMINISTRATION'],
             'time_context_common' => $this->CNF['OBJECT_GRID_TIME_CONTEXT_COMMON'],
             'time_context_administration' => $this->CNF['OBJECT_GRID_TIME_CONTEXT_ADMINISTRATION'],
+            'pre_values' => $this->CNF['OBJECT_GRID_PRE_VALUES'],
         ];
 
         $sPrefix = str_replace('_', '-', $this->_sName);
@@ -284,6 +291,7 @@ class BxTasksConfig extends BxBaseModTextConfig
             'total_popup' => $sPrefix . '-total-popup',
             'timer' => $sPrefix . '-timer-',
             'timer_actions' => $sPrefix . '-timer-actions',
+            'pre_values_popup' => $sPrefix . '-pv-popup-',
         ]);
 
         $this->_bAttachmentsInTimeline = true;

+ 96 - 1
modules/boonex/tasks/classes/BxTasksDb.php

@@ -101,7 +101,7 @@ class BxTasksDb extends BxBaseModTextDb
         $sJoinClause = $sWhereClause = "";
 
         if(($sField = $CNF['FIELD_ALLOW_VIEW_TO']) && $iContextId) {
-            $aBindings[$sField] = $iContextId;
+            $aBindings[$sField] = -$iContextId;
             $sWhereClause .= " AND `te`.`" . $sField . "` = :" . $sField;
         }
 
@@ -438,6 +438,101 @@ class BxTasksDb extends BxBaseModTextDb
         return $this->query("DELETE FROM `" . $CNF['TABLE_TIMERS'] . "` WHERE " . $this->arrayToSQL($aParamsWhere, " AND "));
     }
 
+    public function getPreLists($aParams = []) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = '`tpl`.*';
+        $sJoinClause = $sWhereClause = $sOrderClause = '';
+
+        if(!empty($aParams))
+            switch($aParams['sample']) {
+                case 'name':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = [
+                        'name' => $aParams['name']
+                    ];
+
+                    $sWhereClause = "AND `tpl`.`name` = :name";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = "ORDER BY " . $sOrderClause;
+
+        $aMethod['params'][0] = "SELECT 
+                " . $sSelectClause . " 
+            FROM `" . $CNF['TABLE_PRE_LISTS'] . "` AS `tpl` " . $sJoinClause . " 
+            WHERE 1 " . $sWhereClause . " " . $sOrderClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
+    public function getPreValues($aParams = []) 
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aMethod = ['name' => 'getAll', 'params' => [0 => 'query']];
+        $sSelectClause = '`tpv`.*';
+        $sJoinClause = $sWhereClause = $sOrderClause = '';
+
+        if(!empty($aParams))
+            switch($aParams['sample']) {
+                case 'value_to_use':
+                    $aMethod['name'] = 'getOne';
+                    $aMethod['params'][1] = [
+                        'context_id' => $aParams['context_id'],
+                        'list' => $aParams['list']
+                    ];
+
+                    $sSelectClause = "IF(ISNULL(MAX(`tpv`.`value`)), 0, MAX(`tpv`.`value`)) + 1";
+                    $sWhereClause = "AND `tpv`.`context_id` = :context_id AND `tpv`.`list` = :list";
+                    break;
+
+                case 'id':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = [
+                        'id' => $aParams['id']
+                    ];
+
+                    $sWhereClause = "AND `tpv`.`id` = :id";
+                    break;
+
+                case 'context_list_value':
+                    $aMethod['name'] = 'getRow';
+                    $aMethod['params'][1] = [
+                        'context_id' => $aParams['context_id'],
+                        'list' => $aParams['list'],
+                        'value' => $aParams['value']
+                    ];
+
+                    $sWhereClause = "AND `tpv`.`context_id` = :context_id AND `tpv`.`list` = :list AND `tpv`.`value` = :value";
+                    break;
+
+                case 'context_list':
+                    $aMethod['name'] = 'getAllWithKey';
+                    $aMethod['params'][1] = 'value';
+                    $aMethod['params'][2] = [
+                        'context_id' => $aParams['context_id'],
+                        'list' => $aParams['list']
+                    ];
+
+                    $sWhereClause = "AND `tpv`.`context_id` = :context_id AND `tpv`.`list` = :list";
+                    break;
+            }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = "ORDER BY " . $sOrderClause;
+
+        $aMethod['params'][0] = "SELECT 
+                " . $sSelectClause . " 
+            FROM `" . $CNF['TABLE_PRE_VALUES'] . "` AS `tpv` " . $sJoinClause . " 
+            WHERE 1 " . $sWhereClause . " " . $sOrderClause;
+
+        return call_user_func_array([$this, $aMethod['name']], $aMethod['params']);
+    }
+
     /**
      * Legend: 
      * grp - group

+ 57 - 0
modules/boonex/tasks/classes/BxTasksFormEntry.php

@@ -8,6 +8,14 @@
  * @{
  */
 
+class BxTasksFormEntryChecker extends BxDolFormChecker
+{
+    public function isTrackableField($aInput)
+    {
+        return parent::isTrackableField($aInput) || in_array($aInput['name'], ['stickers', 'type']);
+    }
+}
+
 /**
  * Create/Edit entry form
  */
@@ -23,6 +31,9 @@ class BxTasksFormEntry extends BxBaseModTextFormEntry
     {
         $this->MODULE = 'bx_tasks';
 
+        $aInfo['params'] ??= [];
+        $aInfo['params']['checker'] = 'BxTasksFormEntryChecker';
+
         parent::__construct($aInfo, $oTemplate);
 
         $this->_aProperties = $this->_oModule->_oConfig->getProperties();
@@ -30,7 +41,41 @@ class BxTasksFormEntry extends BxBaseModTextFormEntry
 
     public function setContextId($iContextId)
     {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
         $this->_iContextId = $iContextId;
+
+        if(($sKf = 'FIELD_TYPE') && isset($CNF[$sKf]) && isset($this->aInputs[$CNF[$sKf]])){
+            $aItems = $this->_oModule->_oDb->getPreValues([
+                'sample' => 'context_list', 
+                'context_id' => $this->_iContextId, 
+                'list' => 'type'
+            ]);
+
+            if($aItems && is_array($aItems)) {
+                $this->aInputs[$CNF[$sKf]]['values'] = [
+                    '' => _t('_sys_please_select')
+                ];
+
+                foreach($aItems as $aItem)
+                    $this->aInputs[$CNF[$sKf]]['values'][$aItem['value']] = $aItem['title'];
+            }
+        }
+
+        if(($sKf = 'FIELD_STICKERS') && isset($CNF[$sKf]) && isset($this->aInputs[$CNF[$sKf]])){
+            $aItems = $this->_oModule->_oDb->getPreValues([
+                'sample' => 'context_list', 
+                'context_id' => $this->_iContextId, 
+                'list' => 'sticker'
+            ]);
+
+            if($aItems && is_array($aItems)) {
+                $this->aInputs[$CNF[$sKf]]['values'] = [];
+
+                foreach($aItems as $aItem)
+                    $this->aInputs[$CNF[$sKf]]['values'][$aItem['value']] = $aItem['title'];
+            }
+        }
     }
 
     public function genViewRowValue(&$aInput)
@@ -159,6 +204,18 @@ class BxTasksFormEntry extends BxBaseModTextFormEntry
         return parent::delete($iContentId);
     }
 
+    protected function genCustomViewRowValueStickers (&$aInput)
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        if(empty($aInput['value']) || !is_array($aInput['value']))
+            return '';
+
+        $aStickers = $this->_oModule->getStickers($aInput['value'], $this->_iContextId);
+
+        return $aStickers ? $this->_oModule->_oTemplate->getStickers($aStickers) : '';
+    }
+
     protected function genCustomViewRowValueGhIssueUrl(&$aInput)
     {
         return $aInput['value'] ? bx_linkify(bx_process_output($aInput['value'])) : null;

+ 55 - 0
modules/boonex/tasks/classes/BxTasksFormsEntryHelper.php

@@ -18,6 +18,61 @@ class BxTasksFormsEntryHelper extends BxBaseModTextFormsEntryHelper
         parent::__construct($oModule);
     }
 
+    public function onDataEditBefore ($iContentId, $aContentInfo, &$aTrackTextFieldsChanges, &$oProfile, &$oForm)
+    {
+        parent::onDataEditBefore ($iContentId, $aContentInfo, $aTrackTextFieldsChanges, $oProfile, $oForm);
+
+        $aTrackTextFieldsChanges = [];
+    }
+
+    public function onDataEditAfter ($iContentId, $aContentInfo, $aTrackTextFieldsChanges, $oProfile, $oForm)
+    {
+        if($s = parent::onDataEditAfter($iContentId, $aContentInfo, $aTrackTextFieldsChanges, $oProfile, $oForm))
+            return $s;
+
+        if(!($aContentInfo = $this->_oModule->_oDb->getContentInfoById($iContentId)))
+            return MsgBox(_t('_sys_txt_error_occured'));
+
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aFldLoc2Repo = [
+            $CNF['FIELD_TITLE'] => 'title', 
+            $CNF['FIELD_TEXT'] => 'body',
+            $CNF['FIELD_STICKERS'] => 'labels',
+            $CNF['FIELD_TYPE'] => 'type',
+        ];
+
+        $aFields = [];
+        if(($aLocFields = $aTrackTextFieldsChanges['changed_fields'] ?? false) && is_array($aLocFields))
+            foreach($aLocFields as $sLocField)
+                if(($sRepoField = $aFldLoc2Repo[$sLocField] ?? false)) {
+                    $iContextId = ($iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) < 0 ? abs($iContextId) : 0;
+
+                    switch($sLocField) {
+                        case $CNF['FIELD_STICKERS']:
+                                $aStickers = $this->_oModule->getStickers($aContentInfo[$sLocField], $iContextId);
+                                if($aStickers && is_array($aStickers)) {
+                                    $aFields[$sRepoField] = [];
+                                    foreach($aStickers as $aSticker)
+                                        $aFields[$sRepoField][] = $aSticker['title'];
+                                }
+                                break;
+
+                        case $CNF['FIELD_TYPE']:
+                            $aFields[$sRepoField] = $this->_oModule->getType($aContentInfo[$sLocField], $iContextId);
+                            break;
+
+                        default:
+                            $aFields[$sRepoField] = $aContentInfo[$sLocField];
+                    }
+                }
+
+        if($aFields)
+            $this->_oModule->ghUpdateIssue($aContentInfo, $aFields);
+
+        return '';
+    }
+
     protected function redirectAfterDelete($aContentInfo)
     {
         $CNF = &$this->_oModule->_oConfig->CNF;

+ 248 - 0
modules/boonex/tasks/classes/BxTasksGridPreValues.php

@@ -0,0 +1,248 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT 
+ * @defgroup    Tasks Tasks
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxTasksGridPreValues extends BxBaseModGeneralGrid
+{
+    protected $_iContextPid;
+    
+    protected $_sFilter1Name;   //--- list
+    protected $_sFilter1Value;
+    protected $_aFilter1Values;
+
+    protected $_aListInfo;
+
+    public function __construct ($aOptions, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_tasks';
+
+        parent::__construct ($aOptions, $oTemplate);
+
+        if(($sFfName = 'profile_id') && ($iValue = bx_get($sFfName)) !== false) 
+            $this->setContextPid($iValue);
+
+        /*
+         * Filter by list
+         */
+        $this->_initFilter(1, $this->_oModule->getPreLists());
+
+        if(($sFfName = 'filter') && ($sValue = bx_get($sFfName)) !== false) 
+            $this->_parseFilterValue($sValue);
+
+        if($this->_sFilter1Value)
+            $this->_aListInfo = $this->_oModule->_oDb->getPreLists([
+                'sample' => 'name', 
+                'name' => $this->_sFilter1Value
+            ]);
+    }
+
+    public function setContextPid($iContextPid)
+    {
+        $this->_iContextPid = (int)$iContextPid;
+        $this->_aQueryAppend['profile_id'] = $this->_iContextPid;
+    }
+
+    public function performActionAdd()
+    {
+        if(!$this->_sFilter1Value)
+            return echoJson(['msg' => _t('_bx_tasks_txt_err_empty_pre_list')]);
+
+        $sAction = 'add';
+
+        $oForm = $this->_getForm($sAction);
+        $oForm->initChecker();
+        if($oForm->isSubmittedAndValid()) {
+            if(($iId = (int)$oForm->insert(['context_id' => $this->_iContextPid])) != 0)
+                $aRes = ['grid' => $this->getCode(false), 'blink' => $iId];
+            else
+                $aRes = ['msg' => _t('_bx_tasks_txt_err_cannot_perform_action')];
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds('pre_values_popup') . $sAction, _t('_bx_tasks_popup_pv_title_' . $sAction), $this->_oModule->_oTemplate->parseHtmlByName('popup_pre_values.html', [
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        ]));
+
+        return echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
+    }
+
+    public function performActionEdit()
+    {
+        $sAction = 'edit';
+
+        $aItem = $this->_oModule->_oDb->getPreValues(['sample' => 'id', 'id' => $this->_getIds()]);
+        if(!$aItem)
+            return echoJson([]);
+
+        $oForm = $this->_getForm($sAction, $aItem);
+        $oForm->initChecker($aItem);
+        if($oForm->isSubmittedAndValid()) {
+            if($oForm->update($aItem['id']) !== false)
+                $aRes = ['grid' => $this->getCode(false), 'blink' => $aItem['id']];
+            else
+                $aRes = ['msg' => _t('_bx_tasks_txt_err_cannot_perform_action')];
+
+            return echoJson($aRes);
+        }
+
+        $sContent = BxTemplFunctions::getInstance()->popupBox($this->_oModule->_oConfig->getHtmlIds('pre_values_popup') . $sAction, _t('_bx_tasks_popup_pv_title_' . $sAction), $this->_oModule->_oTemplate->parseHtmlByName('popup_pre_values.html', [
+            'form_id' => $oForm->aFormAttrs['id'],
+            'form' => $oForm->getCode(true),
+            'object' => $this->_sObject,
+            'action' => $sAction
+        ]));
+
+        echoJson(['popup' => ['html' => $sContent, 'options' => ['closeOnOuterClick' => false]]]);
+    }
+
+    protected function _getFilterOnChange()
+    {
+        return $this->_oModule->_oConfig->getJsObject('pre_values') . '.onChangeFilter(this)';
+    }
+
+    protected function _getFilterControls()
+    {
+        parent::_getFilterControls();
+
+        $sContent = $this->_getFilterSelectOne($this->_sFilter1Name, $this->_sFilter1Value, $this->_aFilter1Values, '_bx_tasks_grid_filter_item_title_pv_select_one_list');
+        $sContent .= $this->_getSearchInput();
+        return $sContent;
+    }
+
+    protected function _getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage)
+    {
+        $this->_parseFilterValue($sFilter);
+
+        if(!$this->_iContextPid || !$this->_sFilter1Value)
+            return [];
+
+        $this->_aOptions['source'] .= $this->_oModule->_oDb->prepareAsString(' AND `context_id`=? AND `list`=?', $this->_iContextPid, $this->_sFilter1Value);
+
+        return parent::_getDataSql($sFilter, $sOrderField, $sOrderDir, $iStart, $iPerPage);
+    }
+
+    protected function _getForm($sAction, $aItem = [])
+    {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
+        $aActionParams = [
+            'o' => $this->_sObject, 
+            'a' => $sAction,
+            'profile_id' => $this->_iContextPid,
+            $this->_sFilter1Name => $this->_sFilter1Value
+        ];
+
+        if($aItem)
+            $aActionParams['id'] = $aItem['id'];
+
+        $aForm = [
+            'form_attrs' => [
+                'id' => 'bx-tasks-pre-value-' . $sAction,
+                'action' => BX_DOL_URL_ROOT . bx_append_url_params('grid.php', $aActionParams),
+                'method' => BX_DOL_FORM_METHOD_DEFAULT
+            ],
+            'params' => [
+                'db' => [
+                    'table' => $CNF['TABLE_PRE_VALUES'],
+                    'key' => 'id',
+                    'uri' => '',
+                    'uri_title' => '',
+                    'submit_name' => 'do_submit'
+                ],
+            ],
+            'inputs' => [
+                'list' => [
+                    'type' => 'hidden',
+                    'name' => 'list',
+                    'value' => $this->_sFilter1Value,
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                ],
+                'value' => [
+                    'type' => 'hidden',
+                    'name' => 'value',
+                    'value' => (int)$this->_oModule->_oDb->getPreValues([
+                        'sample' => 'value_to_use', 
+                        'context_id' => $this->_iContextPid, 
+                        'list' => $this->_sFilter1Value
+                    ]),
+                    'db' => [
+                        'pass' => 'Int',
+                    ]
+                ],
+                'title' => [
+                    'type' => 'text',
+                    'name' => 'title',
+                    'caption' => _t('_bx_tasks_form_pv_input_title'),
+                    'value' => '',
+                    'required' => '1',
+                    'db' => [
+                        'pass' => 'Xss',
+                    ],
+                    'checker' => [
+                        'func' => 'Avail',
+                        'params' => [],
+                        'error' => _t('_bx_tasks_form_pv_input_err'),
+                    ],
+                ],
+                'color' => [
+                    'type' => 'text',
+                    'name' => 'color',
+                    'caption' => _t('_bx_tasks_form_pv_input_color'),
+                    'info' => _t('_bx_tasks_form_pv_input_color_inf'),
+                    'value' => '',
+                    'required' => '0',
+                    'db' => [
+                        'pass' => 'Xss',
+                    ]
+                ],
+                'controls' => [
+                    'name' => 'controls',
+                    'type' => 'input_set',
+                    [
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_bx_tasks_form_pv_input_submit'),
+                    ], [
+                        'type' => 'reset',
+                        'name' => 'do_cancel',
+                        'value' => _t('_bx_tasks_form_pv_input_cancel'),
+                        'attrs' => [
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ],
+                    ]
+                ]
+            ]
+        ];
+
+        if($this->_aListInfo && (int)$this->_aListInfo['use_color'] == 0)
+            unset($aForm['inputs']['color']);
+
+        return new BxTemplFormView($aForm);
+    }
+
+    protected function _getIds()
+    {
+        if(($aIds = bx_get('ids')) && is_array($aIds))
+            return reset($aIds);
+
+        if(($iId = bx_get('id')) !== false) 
+            return (int)$iId;
+
+        return false;
+    }
+}
+
+/** @} */

+ 38 - 0
modules/boonex/tasks/classes/BxTasksMenuManageContext.php

@@ -0,0 +1,38 @@
+<?php defined('BX_DOL') or die('hack attempt');
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT 
+ * 
+ * @defgroup    Tasks Tasks
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+class BxTasksMenuManageContext extends BxTemplMenu
+{
+    protected $_sModule;
+    protected $_oModule;
+
+    protected $_sParamName;
+    protected $_iParamValue;
+
+    public function __construct($aObject, $oTemplate = false)
+    {
+        $this->_sModule = 'bx_tasks';
+    	$this->_oModule = BxDolModule::getInstance($this->_sModule);
+
+        parent::__construct($aObject, $oTemplate);
+
+        $this->_sParamName = 'context_pid';
+        if(($iParamValue = bx_get($this->_sParamName)) !== false)
+            $this->_iParamValue = (int)$iParamValue;
+        
+        $this->addMarkers([
+            'js_object_view' => $this->_oModule->_oConfig->getJsObject('tasks'),
+            $this->_sParamName => $this->_iParamValue
+        ]);
+    }
+}
+
+/** @} */

+ 183 - 16
modules/boonex/tasks/classes/BxTasksModule.php

@@ -85,13 +85,12 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
 
     public function actionProcessContextForm($iContextId)
     {
-        $_iContextId = abs($iContextId);
-        if(!$this->isAllowManageByContext($_iContextId))
+        if(!$this->isAllowManageByContext($iContextId))
             return;
 
         $CNF = &$this->_oConfig->CNF;
 
-        $aContext = $this->_oDb->getContexts(['sample' => 'id', 'id' => $_iContextId]);
+        $aContext = $this->_oDb->getContexts(['sample' => 'id', 'id' => $iContextId]);
         $bContext = !empty($aContext) && is_array($aContext);
 
         $oForm = BxDolForm::getObjectInstance($CNF['OBJECT_FORM_CONTEXT'], $CNF['OBJECT_FORM_CONTEXT_DISPLAY_EDIT']);
@@ -99,9 +98,9 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         $oForm->initChecker($aContext);
         if($oForm->isSubmittedAndValid()) {
             if(!$bContext)
-                $oForm->insert(['id' => $_iContextId]);
+                $oForm->insert(['id' => $iContextId]);
             else
-                $oForm->update($_iContextId);
+                $oForm->update($iContextId);
 
             echoJson([
                 'eval' => $this->_oConfig->getJsObject('tasks') . '.hidePopup(oData, ' . $iContextId . ')',
@@ -197,9 +196,7 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
 	
     public function actionProcessTaskForm($iContextId, $iListId)
     {
-        $_iContextId = abs($iContextId);
-
-        if(!$this->isAllowAdd($_iContextId))
+        if(!$this->isAllowAdd($iContextId))
             return echoJson([]);
 
         $CNF = &$this->_oConfig->CNF;
@@ -209,11 +206,11 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
             return echoJson([]);
 
         $oForm->setAction(BX_DOL_URL_ROOT . $this->_oConfig->getBaseUri() . 'process_task_form/' . $iContextId . '/' . $iListId . '/');
-        $oForm->setContextId($_iContextId);
+        $oForm->setContextId($iContextId);
 
         $oForm->initChecker();
         if($oForm->isSubmittedAndValid()) {
-            $iContentId = $oForm->insert([$CNF['FIELD_ALLOW_VIEW_TO'] => $iContextId, $CNF['FIELD_TASKLIST'] => $iListId]);
+            $iContentId = $oForm->insert([$CNF['FIELD_ALLOW_VIEW_TO'] => -$iContextId, $CNF['FIELD_TASKLIST'] => $iListId]);
             if($iContentId)
                 $this->onPublished($iContentId);
 
@@ -452,6 +449,40 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         return $oMenu->getCode();
     }
 
+    public function serviceGetBlockPreValues($iContextPid = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        if(!$this->isAllowManageByContext($iContextPid))
+            return $this->_bIsApi ? [] : '';
+
+        $bContextPid = !empty($iContextPid);
+        
+        $sGrid = $CNF['OBJECT_GRID_PRE_VALUES'];
+        $oGrid = BxDolGrid::getObjectInstance($sGrid);
+        if(!$oGrid)
+            return $this->_bIsApi ? [] : '';
+
+        if($bContextPid)
+            $oGrid->setContextPid($iContextPid);
+
+        if($this->_bIsApi)
+            return [
+                bx_api_get_block('grid', $oGrid->getCodeAPI())
+            ];
+
+        $this->_oTemplate->addCss(['manage_tools.css']);
+        $this->_oTemplate->addJs(['modules/base/text/js/|manage_tools.js', 'pre_values.js']);
+        $this->_oTemplate->addJsTranslation(['_sys_grid_search']);
+        $aResult = [
+            'content' => $this->_oTemplate->getJsCode('pre_values', [
+                'sObjNameGrid' => $sGrid
+            ]) . $oGrid->getCode()
+        ];
+
+        return $aResult;
+    }
+    
     public function serviceGetBlockManageTime($sType = 'common', $iContextPid = 0)
     {
         $CNF = &$this->_oConfig->CNF;
@@ -807,7 +838,7 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         if(!$iContextPid)
             return MsgBox(_t('_Empty'));
 
-        $sContent = $this->serviceBrowseTasks(-$iContextPid);
+        $sContent = $this->serviceBrowseTasks($iContextPid);
         
         if($sContent && ($oProfile = BxDolProfile::getInstance($iContextPid)) !== false)
             return [
@@ -828,12 +859,12 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         if(!$iProfileId)
             return '';
 
-        return $this->serviceBrowseTasks (-$iProfileId, $aParams);
+        return $this->serviceBrowseTasks ($iProfileId, $aParams);
     }
 
     public function serviceBrowseTasks($iContextId = 0, $aParams = [])
     {
-        if(!$this->isAllowView(abs($iContextId)))
+        if(!$this->isAllowView($iContextId))
             return '';
 
         return $this->_oTemplate->getEntriesList($iContextId, $aParams);
@@ -863,6 +894,18 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
 
         return $aResults;
     }
+    
+    public function getPreLists()
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aResults = [];
+        if(($aPreLists = $this->_oDb->getPreLists(['sample' => 'all'])) && is_array($aPreLists))
+            foreach($aPreLists as $aPreList)
+                $aResults[$aPreList['name']] = _t($aPreList['title']);
+
+        return $aResults;
+    }
 
     public function getContexts()
     {
@@ -892,7 +935,7 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         $CNF = &$this->_oConfig->CNF;
 
         $aEntries = [];
-        if(($aTasks = $this->_oDb->getTasks(-$iContextPid)) && is_array($aTasks))
+        if(($aTasks = $this->_oDb->getTasks($iContextPid)) && is_array($aTasks))
             foreach($aTasks as $aTask)
                 $aEntries[$aTask[$CNF['FIELD_ID']]] = $aTask[$CNF['FIELD_TITLE']];
 
@@ -937,11 +980,39 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         $CNF = &$this->_oConfig->CNF;
 
         if(($iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']]) < 0) {
-            $mixedRepo = $this->_oDb->getContextRepository(abs($iContextId));
+            $iContextId = abs($iContextId);
+
+            $mixedRepo = $this->_oDb->getContextRepository($iContextId);
             if($mixedRepo !== false && ($sMl = 'bx_github') && ($sMd = 'create_issue') && bx_is_srv($sMl, $sMd)) {
                 list($sGhUsername, $sGhRepository) = $mixedRepo;
 
-                $aIssue = bx_srv($sMl, $sMd, [$sGhUsername, $sGhRepository, $aContentInfo[$CNF['FIELD_TITLE']], $aContentInfo[$CNF['FIELD_TEXT']]]);
+                $aFldLoc2Repo = [
+                    $CNF['FIELD_STICKERS'] => 'labels', 
+                    $CNF['FIELD_TYPE'] => 'type', 
+                ];
+
+                $aGhFields = [];
+                foreach($aFldLoc2Repo as $sLocField => $sRepoField)
+                    if(($sLocValue = $aContentInfo[$sLocField] ?? false))
+                        switch($sLocField) {
+                            case $CNF['FIELD_STICKERS']:
+                                $aStickers = $this->getStickers($sLocValue, $iContextId);
+                                if($aStickers && is_array($aStickers)) {
+                                    $aGhFields[$sRepoField] = [];
+                                    foreach($aStickers as $aSticker)
+                                        $aGhFields[$sRepoField][] = $aSticker['title'];
+                                }
+                                break;
+
+                            case $CNF['FIELD_TYPE']:
+                                $aGhFields[$sRepoField] = $this->getType($sLocValue, $iContextId);
+                                break;
+
+                            default:
+                                $aGhFields[$sRepoField] = $sLocValue;
+                        }
+
+                $aIssue = bx_srv($sMl, $sMd, [$sGhUsername, $sGhRepository, $aContentInfo[$CNF['FIELD_TITLE']], $aContentInfo[$CNF['FIELD_TEXT']], $aGhFields]);
                 if($aIssue && is_array($aIssue) && ($iNumber = (int)($aIssue['number'] ?? 0)) != 0 && ($sUrl = $aIssue['html_url'] ?? '') != '') {
                     $this->_oDb->updateEntriesBy([
                         $CNF['FIELD_GH_ISSUE'] => $iNumber,
@@ -1131,12 +1202,103 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
         return $oCmts->addAuto($aMessage);
     }
 
+    public function ghUpdateIssue($mixedContent, $aGhFields = [])
+    {
+        $aContentInfo = is_array($mixedContent) ? $mixedContent : $this->_oDb->getContentInfoById((int)$mixedContent);
+        if(!$aContentInfo || !is_array($aContentInfo))
+            return false;
+
+        $CNF = &$this->_oConfig->CNF;
+
+        $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
+        $iContextId = (int)$aContentInfo[$CNF['FIELD_ALLOW_VIEW_TO']];
+        if($iContextId >= 0) 
+            return false;
+
+        $mixedRepo = $this->_oDb->getContextRepository(abs($iContextId));
+        if($mixedRepo === false) 
+            return false;
+
+        list($sGhUsername, $sGhRepository) = $mixedRepo;
+
+        $iGhIssue = (int)$aContentInfo[$CNF['FIELD_GH_ISSUE']];
+
+        $sMl = 'bx_github';
+        if($aGhFields && ($sMd = 'update_issue') && bx_is_srv($sMl, $sMd))
+            if(bx_srv($sMl, $sMd, [$sGhUsername, $sGhRepository, $iGhIssue, $aGhFields]) !== false) 
+                $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_synced', 'markers' => [
+                    'ghi_link' => $aContentInfo[$CNF['FIELD_GH_ISSUE_URL']],
+                    'ghi_number' => $iGhIssue
+                ]]);
+
+        return true;
+    }
+
+    public function getStickers($mixedValues, $iContextId = 0)
+    {
+        $CNF = &$this->_oConfig->CNF;
+
+        $aValues = is_array($mixedValues) ? $mixedValues : BxDolFormCheckerHelper::displaySet($mixedValues);
+
+        $aResults = [];
+        if($iContextId) {
+            $aStickers = $this->_oDb->getPreValues([
+                'sample' => 'context_list', 
+                'context_id' => $iContextId, 
+                'list' => 'sticker'
+            ]);
+
+            foreach($aValues as $sValue)
+                if(($aSticker = $aStickers[$sValue] ?? false))
+                    $aResults[] = [
+                        'title' => $aSticker['title'],
+                        'color' => $aSticker['color']
+                    ];
+        }
+
+        if(!$aResults) {
+            $aStickers = BxDolForm::getDataItems($CNF['OBJECT_PRE_LIST_STICKERS']);
+            foreach($aValues as $sValue)
+                $aResults[] = [
+                    'title' => $aStickers[$sValue],
+                    'color' => ''
+                ];
+        }
+
+        return $aResults;
+    }
+
+    public function getType($mixedValue, $iContextId = 0)
+    {
+        $sResult = '';
+
+        if($iContextId) {
+            $aType = $this->_oDb->getPreValues([
+                'sample' => 'context_list_value', 
+                'context_id' => $iContextId, 
+                'list' => 'type',
+                'value' => $mixedValue
+            ]);
+
+            if($aType && is_array($aType))
+                $sResult = $aType['title'];
+        }
+        
+        if(!$sResult && ($sTypeTitle = $this->_oConfig->getTypeTitle($mixedValue)) != '')
+            $sResult = _t($sTypeTitle);
+
+        return $sResult;
+    }
+
     /**
      * Internal methods
      */
     protected function _onEditProperty($aContentInfo, $sProperty, &$oForm)
     {
         $CNF = &$this->_oConfig->CNF;
+        $aPropLoc2Repo = [
+            $CNF['FIELD_TYPE'] => 'type',
+        ];
 
         $iContentId = (int)$aContentInfo[$CNF['FIELD_ID']];
 
@@ -1145,6 +1307,11 @@ class BxTasksModule extends BxBaseModTextModule implements iBxDolCalendarService
             $mixedValue = $this->_oConfig->$sMethod($mixedValue);
 
         $this->logActivity($iContentId, ['key' => '_bx_tasks_txt_msg_edit_' . $sProperty, 'markers' => ['value' => $mixedValue]]);
+
+        if(($sPropRepo = $aPropLoc2Repo[$sProperty] ?? false))
+            $this->ghUpdateIssue($aContentInfo, [
+                $sPropRepo => _t($mixedValue)
+            ]);        
     }
 
     protected function _onEditState($aContentInfo, &$oForm)

+ 23 - 6
modules/boonex/tasks/classes/BxTasksTemplate.php

@@ -242,9 +242,8 @@ class BxTasksTemplate extends BxBaseModTextTemplate
 
         $oModule = $this->getModule();
 
-        $_iContextId = abs($iContextId);
-        $bAllowAdd = $oModule->isAllowAdd($_iContextId);
-        $bAllowManage = $oModule->isAllowManageByContext($_iContextId);
+        $bAllowAdd = $oModule->isAllowAdd($iContextId);
+        $bAllowManage = $oModule->isAllowManageByContext($iContextId);
 
         $aTmplVarsFilterItems = [];
 
@@ -314,9 +313,8 @@ class BxTasksTemplate extends BxBaseModTextTemplate
         $aPriorities = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_PRIORITIES']);
         $aStates = BxDolFormQuery::getDataItems($CNF['OBJECT_PRE_LIST_STATES']);
 
-        $_iContextId = abs($iContextId);
-        $bAllowAdd = $oModule->isAllowAdd($_iContextId);
-        $bAllowManage = $oModule->isAllowManageByContext($_iContextId);
+        $bAllowAdd = $oModule->isAllowAdd($iContextId);
+        $bAllowManage = $oModule->isAllowManageByContext($iContextId);
 
         $aTmplVarsLists = [];
 
@@ -429,6 +427,25 @@ class BxTasksTemplate extends BxBaseModTextTemplate
             'bx_repeat:task_lists' => $aTmplVarsLists,
         ]);
     }
+
+    public function getStickers($aStickers)
+    {
+        $aTmplVarsStickers = [];
+        foreach($aStickers as $aSticker)
+            $aTmplVarsStickers[] = [
+                'title' => $aSticker['title'],
+                'bx_if:show_color' => [
+                    'condition' => $aSticker['color'] != '',
+                    'content' => [
+                        'color' => $aSticker['color']
+                    ]
+                ]
+            ];
+
+        return $this->parseHtmlByName('stickers.html', [
+            'bx_repeat:stickers' => $aTmplVarsStickers
+        ]);
+    }
 }
 
 /** @} */

+ 36 - 3
modules/boonex/tasks/install/langs/en.xml

@@ -41,6 +41,8 @@
     <string name="_bx_tasks_form_entry_input_sys_title"><![CDATA[Title]]></string>
     <string name="_bx_tasks_form_entry_input_title"><![CDATA[Title]]></string>
     <string name="_bx_tasks_form_entry_input_title_err"><![CDATA[Title is essential. Please, fill in this field]]></string>
+    <string name="_bx_tasks_form_entry_input_sys_stickers"><![CDATA[Labels]]></string>
+    <string name="_bx_tasks_form_entry_input_stickers"><![CDATA[Labels]]></string>
     <string name="_bx_tasks_form_entry_input_sys_type"><![CDATA[Type]]></string>
     <string name="_bx_tasks_form_entry_input_type"><![CDATA[Type]]></string>
     <string name="_bx_tasks_form_entry_input_sys_priority"><![CDATA[Priority]]></string>
@@ -143,6 +145,15 @@
     <string name="_bx_tasks_popup_title_time_add"><![CDATA[Add Time]]></string>
     <string name="_bx_tasks_popup_title_time_edit"><![CDATA[Edit Time]]></string>    
 
+    <string name="_bx_tasks_form_pv_input_title"><![CDATA[Title]]></string>
+    <string name="_bx_tasks_form_pv_input_color"><![CDATA[Color]]></string>
+    <string name="_bx_tasks_form_pv_input_color_inf"><![CDATA[Use RGB color code.]]></string>
+    <string name="_bx_tasks_form_pv_input_submit"><![CDATA[Submit]]></string>
+    <string name="_bx_tasks_form_pv_input_cancel"><![CDATA[Cancel]]></string>
+    <string name="_bx_tasks_form_pv_input_err"><![CDATA[This field is essential. Please, fill it in.]]></string>
+    <string name="_bx_tasks_popup_pv_title_add"><![CDATA[Add Value]]></string>
+    <string name="_bx_tasks_popup_pv_title_edit"><![CDATA[Edit Value]]></string>
+
     <string name="_bx_tasks_category_form_entry"><![CDATA[Categories Form]]></string>
     <string name="_bx_tasks_category_display_add"><![CDATA[Add category]]></string>
     <string name="_bx_tasks_category_display_edit"><![CDATA[Edit category]]></string>
@@ -275,6 +286,10 @@
     <string name="_bx_tasks_page_block_title_entries_time_in_context"><![CDATA[My Time in <a href="{profile_link}">{display_name}</a>]]></string>
     <string name="_bx_tasks_page_block_title_sys_entries_time_in_context_administration"><![CDATA[All time in context]]></string>
     <string name="_bx_tasks_page_block_title_entries_time_in_context_administration"><![CDATA[All Time in <a href="{profile_link}">{display_name}</a>]]></string>
+    <string name="_bx_tasks_page_title_sys_context_pre_values"><![CDATA[Lists and values in context]]></string>
+    <string name="_bx_tasks_page_title_context_pre_values"><![CDATA[Lists and values]]></string>
+    <string name="_bx_tasks_page_block_title_system_context_pre_values"><![CDATA[Lists and values]]></string>
+    <string name="_bx_tasks_page_block_title_context_pre_values"><![CDATA[Lists and values]]></string>
     <string name="_bx_tasks_page_block_title_system_menu_browse"><![CDATA[Browse menu]]></string>
     <string name="_bx_tasks_page_block_title_menu_browse"><![CDATA[Browse]]></string>
 
@@ -354,6 +369,12 @@
     <string name="_bx_tasks_menu_item_title_view_context_time"><![CDATA[My Time]]></string>
     <string name="_bx_tasks_menu_item_title_system_view_context_time_administration"><![CDATA[All Time]]></string>
     <string name="_bx_tasks_menu_item_title_view_context_time_administration"><![CDATA[All Time]]></string>
+    <string name="_bx_tasks_menu_title_manage_context_submenu"><![CDATA[Manage Context Submenu]]></string>
+    <string name="_bx_tasks_menu_set_title_manage_context_submenu"><![CDATA[Manage Context Submenu]]></string>
+    <string name="_bx_tasks_menu_item_title_system_manage_context_pre_values"><![CDATA[Lists and values]]></string>
+    <string name="_bx_tasks_menu_item_title_manage_context_pre_values"><![CDATA[Lists and values]]></string>
+    <string name="_bx_tasks_menu_item_title_system_manage_context_settings"><![CDATA[Settings]]></string>
+    <string name="_bx_tasks_menu_item_title_manage_context_settings"><![CDATA[Settings]]></string>
     <string name="_bx_tasks_menu_title_manage_tools_submenu"><![CDATA[Manage Tools Submenu]]></string>
     <string name="_bx_tasks_menu_set_title_manage_tools_submenu"><![CDATA[Manage Tools Submenu]]></string>
     <string name="_bx_tasks_menu_item_title_mt_submenu_entries_common"><![CDATA[My Tasks]]></string>
@@ -401,6 +422,14 @@
     <string name="_bx_tasks_grid_filter_item_title_tm_select_one_context_module"><![CDATA[Any Module]]></string>
     <string name="_bx_tasks_grid_filter_item_title_tm_select_one_object_id"><![CDATA[Any Task]]></string>
 
+    <string name="_bx_tasks_grid_column_title_pv_title"><![CDATA[Title]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_add"><![CDATA[Add]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_edit"><![CDATA[Edit]]></string>
+    <string name="_bx_tasks_grid_action_title_pv_delete"><![CDATA[Delete]]></string>
+    <string name="_bx_tasks_grid_filter_item_title_pv_select_one_list"><![CDATA[Select list...]]></string>
+
+
+    <!-- Charts -->
     <string name="_bx_tasks_chart_growth"><![CDATA[Tasks: Growth]]></string>
     <string name="_bx_tasks_chart_growth_speed"><![CDATA[Tasks: Growth Speed]]></string>
 
@@ -419,6 +448,12 @@
     <string name="_bx_tasks_type_1"><![CDATA[Bug]]></string>
     <string name="_bx_tasks_type_2"><![CDATA[Feature]]></string>
     <string name="_bx_tasks_type_3"><![CDATA[Chore]]></string>
+    <string name="_bx_tasks_pre_lists_stickers"><![CDATA[Labels]]></string>
+    <string name="_bx_tasks_sticker_1"><![CDATA[Bug]]></string>
+    <string name="_bx_tasks_sticker_2"><![CDATA[Feature]]></string>
+    <string name="_bx_tasks_sticker_3"><![CDATA[Improvement]]></string>
+    <string name="_bx_tasks_sticker_4"><![CDATA[Investigation]]></string>
+    <string name="_bx_tasks_sticker_5"><![CDATA[Discussion]]></string>
     <string name="_bx_tasks_pre_lists_priorities"><![CDATA[Priorities]]></string>
     <string name="_bx_tasks_priority_1"><![CDATA[Urgent]]></string>
     <string name="_bx_tasks_priority_2"><![CDATA[High]]></string>
@@ -492,7 +527,6 @@
     <string name="_bx_tasks_txt_processing_failed"><![CDATA[Task isn't published because video conversion failed, edit video to fix the issue.]]></string>
     <string name="_bx_tasks_txt_scheduled_awaiting"><![CDATA[Task publishing date is {date_publish_uf}]]></string>
     <string name="_bx_tasks_txt_new_task_list"><![CDATA[New Task List]]></string>
-    <string name="_bx_tasks_txt_new_settings"><![CDATA[Settings]]></string>
     <string name="_bx_tasks_txt_new_task"><![CDATA[New Task]]></string>
     <string name="_bx_tasks_txt_total"><![CDATA[Total: {0}]]></string>
     <string name="_bx_tasks_txt_estimate"><![CDATA[Estimate: {0}]]></string>
@@ -505,11 +539,10 @@
     <string name="_bx_tasks_txt_timer_log"><![CDATA[Log]]></string>
 
     <string name="_bx_tasks_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
-    <string name="_bx_tasks_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+    <string name="_bx_tasks_txt_err_empty_pre_list"><![CDATA[Please select a list to add items to.]]></string>
     <string name="_bx_tasks_txt_msg_status_hidden"><![CDATA[This task was hidden.]]></string>
     <string name="_bx_tasks_txt_msg_status_pending"><![CDATA[This task is pending approval.]]></string>
     <string name="_bx_tasks_txt_msg_confirm_tasklist_deletion"><![CDATA[You will delete all tasks that are contained in this tasklist. Are you sure?]]></string>
-
     <string name="_bx_tasks_txt_msg_format"><![CDATA[{0} &#183; <span>{1}</span>]]></string>
     <string name="_bx_tasks_txt_msg_synced"><![CDATA[The task was synced with GitHub: <b><a href="{ghi_link}" target="_blank">#{ghi_number}</a></b>]]></string>
     <string name="_bx_tasks_txt_msg_edit_type"><![CDATA[<a href="{author_link}">{author_name}</a> changed type to <b>{value}</b>]]></string>

+ 2 - 2
modules/boonex/tasks/install/sql/disable.sql

@@ -8,12 +8,12 @@ DELETE FROM `sys_options_types` WHERE `id` = @iTypeId;
 
 -- PAGES
 DELETE FROM `sys_objects_page` WHERE `module` = 'bx_tasks';
-DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_tasks' OR `object` IN('bx_tasks_create_entry', 'bx_tasks_edit_entry', 'bx_tasks_delete_entry', 'bx_tasks_view_entry', 'bx_tasks_view_entry_comments', 'bx_tasks_context', 'bx_tasks_manage', 'bx_tasks_administration', 'bx_tasks_time_manage', 'bx_tasks_time_administration', 'bx_tasks_context_time', 'bx_tasks_context_time_administration');
+DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_tasks' OR `object` IN('bx_tasks_create_entry', 'bx_tasks_edit_entry', 'bx_tasks_delete_entry', 'bx_tasks_view_entry', 'bx_tasks_view_entry_comments', 'bx_tasks_context', 'bx_tasks_manage', 'bx_tasks_administration', 'bx_tasks_time_manage', 'bx_tasks_time_administration', 'bx_tasks_context_time', 'bx_tasks_context_time_administration', 'bx_tasks_context_pre_values', 'bx_tasks_timers');
 
 -- MENU
 DELETE FROM `sys_objects_menu` WHERE `module` = 'bx_tasks';
 DELETE FROM `sys_menu_sets` WHERE `module` = 'bx_tasks';
-DELETE FROM `sys_menu_items` WHERE `module` = 'bx_tasks' OR `set_name` IN('bx_tasks_create_task_attachments', 'bx_tasks_view', 'bx_tasks_view_actions', 'bx_tasks_view_submenu', 'bx_tasks_view_context_submenu', 'bx_tasks_menu_manage_tools', 'bx_tasks_manage_tools_submenu', 'bx_tasks_browse');
+DELETE FROM `sys_menu_items` WHERE `module` = 'bx_tasks' OR `set_name` IN('bx_tasks_create_task_attachments', 'bx_tasks_view', 'bx_tasks_view_actions', 'bx_tasks_view_submenu', 'bx_tasks_view_context_submenu', 'bx_tasks_manage_context_submenu', 'bx_tasks_menu_manage_tools', 'bx_tasks_manage_tools_submenu', 'bx_tasks_browse');
 
 -- PRIVACY 
 DELETE FROM `sys_objects_privacy` WHERE `object` = 'bx_tasks_allow_view_to';

+ 41 - 1
modules/boonex/tasks/install/sql/enable.sql

@@ -110,6 +110,13 @@ INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `t
 ('bx_tasks_context_time_administration', 2, 'bx_tasks', '_bx_tasks_page_block_title_sys_menu_in_context', '_bx_tasks_page_block_title_menu_in_context', 13, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:22:"get_block_menu_context";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 1, 1),
 ('bx_tasks_context_time_administration', 3, 'bx_tasks', '_bx_tasks_page_block_title_sys_entries_time_in_context_administration', '_bx_tasks_page_block_title_entries_time_in_context_administration', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:21:"get_block_manage_time";s:6:"params";a:2:{i:0;s:14:"administration";i:1;s:12:"{profile_id}";}}', 0, 0, 1, 1);
 
+-- PAGE: pre lists and values
+INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
+('bx_tasks_context_pre_values', '_bx_tasks_page_title_sys_context_pre_values', '_bx_tasks_page_title_context_pre_values', 'bx_tasks', 5, 2147483647, 1, 'tasks-context-values', 'page.php?i=tasks-context-values', '', '', '', 0, 1, 0, 'BxTasksPageAuthor', 'modules/boonex/tasks/classes/BxTasksPageAuthor.php');
+
+INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
+('bx_tasks_context_pre_values', 1, 'bx_tasks', '_bx_tasks_page_block_title_system_context_pre_values', '_bx_tasks_page_block_title_context_pre_values', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:20:"get_block_pre_values";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 1, 0);
+
 -- PAGE: manage own entries
 INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `layout_id`, `visible_for_levels`, `visible_for_levels_editable`, `uri`, `url`, `meta_description`, `meta_keywords`, `meta_robots`, `cache_lifetime`, `cache_editable`, `deletable`, `override_class_name`, `override_class_file`) VALUES 
 ('bx_tasks_manage', '_bx_tasks_page_title_sys_manage', '_bx_tasks_page_title_manage', 'bx_tasks', 5, 2147483647, 1, 'tasks-manage', 'page.php?i=tasks-manage', '', '', '', 0, 1, 0, 'BxTasksPageBrowse', 'modules/boonex/tasks/classes/BxTasksPageBrowse.php');
@@ -233,6 +240,17 @@ INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `titl
 ('bx_tasks_view_context_submenu', 'bx_tasks', 'tasks-context-time', '_bx_tasks_menu_item_title_system_view_context_time', '_bx_tasks_menu_item_title_view_context_time', 'page.php?i=tasks-context-time&profile_id={profile_id}', '', '', '', '', 2147483647, '', 1, 0, 2),
 ('bx_tasks_view_context_submenu', 'bx_tasks', 'tasks-context-time-administration', '_bx_tasks_menu_item_title_system_view_context_time_administration', '_bx_tasks_menu_item_title_view_context_time_administration', 'page.php?i=tasks-context-time-administration&profile_id={profile_id}', '', '', '', '', 2147483647, 'a:3:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:31:"check_allowed_manage_in_context";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 1, 0, 3);
 
+-- MENU: manage context sub-menu
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_tasks_manage_context_submenu', '_bx_tasks_menu_title_manage_context_submenu', 'bx_tasks_manage_context_submenu', 'bx_tasks', 6, 0, 1, 'BxTasksMenuManageContext', 'modules/boonex/tasks/classes/BxTasksMenuManageContext.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_tasks_manage_context_submenu', 'bx_tasks', '_bx_tasks_menu_set_title_manage_context_submenu', 0);
+
+INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `visibility_custom`, `active`, `copyable`, `order`) VALUES 
+('bx_tasks_manage_context_submenu', 'bx_tasks', 'tasks-context-values', '_bx_tasks_menu_item_title_system_manage_context_pre_values', '_bx_tasks_menu_item_title_manage_context_pre_values', 'page.php?i=tasks-context-values&profile_id={context_pid}', '', '', '', '', 2147483647, '', 1, 0, 1),
+('bx_tasks_manage_context_submenu', 'bx_tasks', 'tasks-context-settings', '_bx_tasks_menu_item_title_system_manage_context_settings', '_bx_tasks_menu_item_title_manage_context_settings', 'javascript:void(0)', '{js_object_view}.processContext({context_pid}, this)', '', '', '', 2147483647, '', 1, 0, 2);
+
 -- MENU: manage tools submenu
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
 ('bx_tasks_manage_tools_submenu', '_bx_tasks_menu_title_manage_tools_submenu', 'bx_tasks_manage_tools_submenu', 'bx_tasks', 26, 0, 1, '', '');
@@ -264,6 +282,13 @@ INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `templat
 INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
 ('bx_tasks_browse', 'bx_tasks', '_bx_tasks_menu_set_title_browse', 0);
 
+-- MENU: 
+INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
+('bx_tasks_browse', '_bx_tasks_menu_title_browse', 'bx_tasks_browse', 'bx_tasks', 32, 0, 1, 'BxTasksMenuBrowse', 'modules/boonex/tasks/classes/BxTasksMenuBrowse.php');
+
+INSERT INTO `sys_menu_sets`(`set_name`, `module`, `title`, `deletable`) VALUES 
+('bx_tasks_browse', 'bx_tasks', '_bx_tasks_menu_set_title_browse', 0);
+
 -- MENU: add menu item to profiles modules (trigger* menu sets are processed separately upon modules enable/disable)
 INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
 ('trigger_group_view_submenu', 'bx_tasks', 'tasks-context', '_bx_tasks_menu_item_title_system_view_entries_in_context', '_bx_tasks_menu_item_title_view_entries_in_context', 'page.php?i=tasks-context&profile_id={profile_id}', '', '', 'tasks', '', 510, 1, 0, 0);
@@ -469,8 +494,23 @@ INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon
 ('bx_tasks_time_context_common', 'single', 'edit', '_bx_tasks_grid_action_title_tm_edit', 'pencil-alt', 1, 0, 1),
 ('bx_tasks_time_context_common', 'single', 'delete', '_bx_tasks_grid_action_title_tm_delete', 'remove', 1, 1, 2);
 
--- UPLOADERS
+-- GRIDS: pre lists and values
+INSERT INTO `sys_objects_grid` (`object`, `source_type`, `source`, `table`, `field_id`, `field_order`, `field_active`, `paginate_url`, `paginate_per_page`, `paginate_simple`, `paginate_get_start`, `paginate_get_per_page`, `filter_fields`, `filter_fields_translatable`, `filter_mode`, `sorting_fields`, `sorting_fields_translatable`, `visible_for_levels`, `override_class_name`, `override_class_file`) VALUES
+('bx_tasks_pre_values', 'Sql', 'SELECT `tpv`.*, `tpl`.`title` AS `list_title`, `tpl`.`use_color` AS `list_color`, `tpl`.`use_multiselect` AS `list_multiselect` FROM `bx_tasks_pre_values` AS `tpv` INNER JOIN `bx_tasks_pre_lists` AS `tpl` ON `tpv`.`list`=`tpl`.`name` WHERE 1 ', 'bx_tasks_pre_values', 'id', 'order', '', '', 20, NULL, 'start', '', 'tpv`.`name,tpv`.`title,tpl`.`title', '', 'like', '', '', 2147483647, 'BxTasksGridPreValues', 'modules/boonex/tasks/classes/BxTasksGridPreValues.php');
 
+INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
+('bx_tasks_pre_values', 'order', '', '10%', 0, 0, '', 1),
+('bx_tasks_pre_values', 'title', '_bx_tasks_grid_column_title_pv_title', '70%', 0, 0, '', 2),
+('bx_tasks_pre_values', 'actions', '', '20%', 0, 0, '', 3);
+
+INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
+('bx_tasks_pre_values', 'independent', 'add', '_bx_tasks_grid_action_title_pv_add', '', 0, 0, 1),
+('bx_tasks_pre_values', 'bulk', 'delete', '_bx_tasks_grid_action_title_pv_delete', '', 0, 1, 1),
+('bx_tasks_pre_values', 'single', 'edit', '_bx_tasks_grid_action_title_pv_edit', 'pencil-alt', 1, 0, 1),
+('bx_tasks_pre_values', 'single', 'delete', '_bx_tasks_grid_action_title_pv_delete', 'remove', 1, 1, 2);
+
+
+-- UPLOADERS
 INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES
 ('bx_tasks_html5', 1, 'BxTasksUploaderHTML5', 'modules/boonex/tasks/classes/BxTasksUploaderHTML5.php'),
 ('bx_tasks_record_video', 1, 'BxTasksUploaderRecordVideo', 'modules/boonex/tasks/classes/BxTasksUploaderRecordVideo.php'),

+ 64 - 21
modules/boonex/tasks/install/sql/install.sql

@@ -7,6 +7,7 @@ CREATE TABLE IF NOT EXISTS `bx_tasks_tasks` (
   `published` int(11) NOT NULL,
   `thumb` int(11) NOT NULL,
   `title` varchar(255) NOT NULL,
+  `stickers` int(11) NOT NULL default '0',
   `type` int(11) NOT NULL default '0',
   `priority` int(11) NOT NULL default '0',
   `estimate` int(11) NOT NULL default '0',
@@ -70,6 +71,33 @@ CREATE TABLE IF NOT EXISTS `bx_tasks_assignments` (
   KEY `content` (`content`)
 );
 
+-- TABLE: lists and values
+CREATE TABLE IF NOT EXISTS `bx_tasks_pre_lists` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `name` varchar(32) NOT NULL DEFAULT '',
+  `title` varchar(255) NOT NULL DEFAULT '',
+  `use_color` tinyint(4) unsigned NOT NULL DEFAULT '0',
+  `use_multiselect` tinyint(4) unsigned NOT NULL DEFAULT '0',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `name` (`name`)
+);
+
+INSERT INTO `bx_tasks_pre_lists` (`name`, `title`, `use_color`, `use_multiselect`) VALUES
+('type', '_bx_tasks_pre_lists_types', 0, 0),
+('sticker', '_bx_tasks_pre_lists_stickers', 1, 1);
+
+CREATE TABLE IF NOT EXISTS `bx_tasks_pre_values` (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `context_id` int(11) NOT NULL DEFAULT '0',
+  `list` varchar(32) NOT NULL DEFAULT '',
+  `value` varchar(255) NOT NULL DEFAULT '',
+  `order` int(11) NOT NULL DEFAULT '0',
+  `title` varchar(255) NOT NULL DEFAULT '',
+  `color` text NOT NULL DEFAULT '',
+  PRIMARY KEY (`id`),
+  UNIQUE KEY `list_value` (`list`, `value`)
+);
+
 -- TABLE: filters
 CREATE TABLE IF NOT EXISTS `bx_tasks_filters` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -470,6 +498,7 @@ INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `ch
 ('bx_tasks', 'bx_tasks', 'files', 'a:1:{i:0;s:20:"bx_tasks_files_html5";}', 'a:1:{s:20:"bx_tasks_files_html5";s:25:"_sys_uploader_html5_title";}', 0, 'files', '_bx_tasks_form_entry_input_sys_files', '_bx_tasks_form_entry_input_files', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_tasks', 'bx_tasks', 'text', '', '', 0, 'textarea', '_bx_tasks_form_entry_input_sys_text', '_bx_tasks_form_entry_input_text', '', 0, 0, 2, '', '', '', '', '', '', 'XssHtml', '', 1, 0),
 ('bx_tasks', 'bx_tasks', 'title', '', '', 0, 'text', '_bx_tasks_form_entry_input_sys_title', '_bx_tasks_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_tasks_form_entry_input_title_err', 'Xss', '', 1, 0),
+('bx_tasks', 'bx_tasks', 'stickers', '', '#!bx_tasks_stickers', 0, 'checkbox_set', '_bx_tasks_form_entry_input_sys_stickers', '_bx_tasks_form_entry_input_stickers', '', 0, 0, 0, '', '', '', '', '', '', 'Set', '', 1, 0),
 ('bx_tasks', 'bx_tasks', 'type', '', '#!bx_tasks_types', 0, 'select', '_bx_tasks_form_entry_input_sys_type', '_bx_tasks_form_entry_input_type', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_tasks', 'bx_tasks', 'priority', '', '#!bx_tasks_priorities', 0, 'select', '_bx_tasks_form_entry_input_sys_priority', '_bx_tasks_form_entry_input_priority', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_tasks', 'bx_tasks', 'state', '', '#!bx_tasks_states', 0, 'select', '_bx_tasks_form_entry_input_sys_state', '_bx_tasks_form_entry_input_state', '', 0, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
@@ -492,12 +521,13 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_tasks_entry_add', 'text', 2147483647, 1, 2),
 ('bx_tasks_entry_add', 'initial_members', 192, 1, 3),
 ('bx_tasks_entry_add', 'due_date', 192, 1, 4),
-('bx_tasks_entry_add', 'type', 2147483647, 1, 5),
-('bx_tasks_entry_add', 'priority', 2147483647, 1, 6),
-('bx_tasks_entry_add', 'estimate', 2147483647, 1, 7),
-('bx_tasks_entry_add', 'controls', 2147483647, 1, 8),
-('bx_tasks_entry_add', 'do_publish', 2147483647, 1, 9),
-('bx_tasks_entry_add', 'do_cancel', 2147483647, 1, 10),
+('bx_tasks_entry_add', 'stickers', 2147483647, 1, 5),
+('bx_tasks_entry_add', 'type', 2147483647, 1, 6),
+('bx_tasks_entry_add', 'priority', 2147483647, 1, 7),
+('bx_tasks_entry_add', 'estimate', 2147483647, 1, 8),
+('bx_tasks_entry_add', 'controls', 2147483647, 1, 9),
+('bx_tasks_entry_add', 'do_publish', 2147483647, 1, 10),
+('bx_tasks_entry_add', 'do_cancel', 2147483647, 1, 11),
 
 ('bx_tasks_entry_delete', 'delete_confirm', 2147483647, 1, 1),
 ('bx_tasks_entry_delete', 'do_submit', 2147483647, 1, 2),
@@ -512,12 +542,13 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_tasks_entry_edit', 'cf', 2147483647, 1, 8),
 ('bx_tasks_entry_edit', 'initial_members', 192, 1, 9),
 ('bx_tasks_entry_edit', 'due_date', 192, 1, 10),
-('bx_tasks_entry_edit', 'type', 2147483647, 1, 11),
-('bx_tasks_entry_edit', 'priority', 2147483647, 1, 12),
-('bx_tasks_entry_edit', 'estimate', 2147483647, 1, 13),
-('bx_tasks_entry_edit', 'controls_edit', 2147483647, 1, 14),
-('bx_tasks_entry_edit', 'do_submit', 2147483647, 1, 15),
-('bx_tasks_entry_edit', 'do_cancel_edit', 2147483647, 1, 16),
+('bx_tasks_entry_edit', 'stickers', 2147483647, 1, 11),
+('bx_tasks_entry_edit', 'type', 2147483647, 1, 12),
+('bx_tasks_entry_edit', 'priority', 2147483647, 1, 13),
+('bx_tasks_entry_edit', 'estimate', 2147483647, 1, 14),
+('bx_tasks_entry_edit', 'controls_edit', 2147483647, 1, 15),
+('bx_tasks_entry_edit', 'do_submit', 2147483647, 1, 16),
+('bx_tasks_entry_edit', 'do_cancel_edit', 2147483647, 1, 17),
 
 ('bx_tasks_entry_edit_body', 'title', 2147483647, 1, 1),
 ('bx_tasks_entry_edit_body', 'text', 2147483647, 1, 2),
@@ -548,15 +579,16 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_tasks_entry_edit_due_date', 'do_submit', 2147483647, 1, 3),
 ('bx_tasks_entry_edit_due_date', 'do_cancel', 2147483647, 1, 4),
 
-('bx_tasks_entry_view', 'type', 2147483647, 1, 1),
-('bx_tasks_entry_view', 'priority', 2147483647, 1, 2),
-('bx_tasks_entry_view', 'estimate', 2147483647, 1, 3),
-('bx_tasks_entry_view', 'cat', 2147483647, 1, 4),
-('bx_tasks_entry_view', 'added', 2147483647, 1, 5),
-('bx_tasks_entry_view', 'changed', 2147483647, 1, 6),
-('bx_tasks_entry_view', 'due_date', 192, 1, 7),
-('bx_tasks_entry_view', 'state', 2147483647, 1, 8),
-('bx_tasks_entry_view', 'gh_issue_url', 2147483647, 1, 9);
+('bx_tasks_entry_view', 'stickers', 2147483647, 1, 1),
+('bx_tasks_entry_view', 'type', 2147483647, 1, 2),
+('bx_tasks_entry_view', 'priority', 2147483647, 1, 3),
+('bx_tasks_entry_view', 'estimate', 2147483647, 1, 4),
+('bx_tasks_entry_view', 'cat', 2147483647, 1, 5),
+('bx_tasks_entry_view', 'added', 2147483647, 1, 6),
+('bx_tasks_entry_view', 'changed', 2147483647, 1, 7),
+('bx_tasks_entry_view', 'due_date', 192, 1, 8),
+('bx_tasks_entry_view', 'state', 2147483647, 1, 9),
+('bx_tasks_entry_view', 'gh_issue_url', 2147483647, 1, 10);
 
 
 -- FORMS: entry (tasklist)
@@ -661,6 +693,17 @@ INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALU
 ('bx_tasks_types', '2', 2, '_bx_tasks_type_2', ''),
 ('bx_tasks_types', '3', 3, '_bx_tasks_type_3', '');
 
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_tasks_stickers', '_bx_tasks_pre_lists_stickers', 'bx_tasks', '1');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_tasks_stickers', '', 0, '_sys_please_select', ''),
+('bx_tasks_stickers', '1', 1, '_bx_tasks_sticker_1', ''),
+('bx_tasks_stickers', '2', 2, '_bx_tasks_sticker_2', ''),
+('bx_tasks_stickers', '3', 3, '_bx_tasks_sticker_3', ''),
+('bx_tasks_stickers', '4', 4, '_bx_tasks_sticker_4', ''),
+('bx_tasks_stickers', '5', 5, '_bx_tasks_sticker_5', '');
+
 INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
 ('bx_tasks_priorities', '_bx_tasks_pre_lists_priorities', 'bx_tasks', '0');
 

+ 1 - 1
modules/boonex/tasks/install/sql/uninstall.sql

@@ -1,6 +1,6 @@
 
 -- TABLES
-DROP TABLE IF EXISTS `bx_tasks_tasks`, `bx_tasks_lists`, `bx_tasks_contexts`, `bx_tasks_assignments`, `bx_tasks_filters`, `bx_tasks_covers`, `bx_tasks_files`, `bx_tasks_photos`, `bx_tasks_photos_resized`, `bx_tasks_videos`, `bx_tasks_videos_resized`, `bx_tasks_cmts`, `bx_tasks_cmts_notes`, `bx_tasks_votes`, `bx_tasks_votes_track`, `bx_tasks_reactions`, `bx_tasks_reactions_track`, `bx_tasks_views_track`, `bx_tasks_meta_keywords`, `bx_tasks_meta_locations`, `bx_tasks_meta_mentions`, `bx_tasks_reports`, `bx_tasks_reports_track`, `bx_tasks_time`, `bx_tasks_time_track`, `bx_tasks_timers`, `bx_tasks_favorites_track`, `bx_tasks_scores`, `bx_tasks_scores_track`;
+DROP TABLE IF EXISTS `bx_tasks_tasks`, `bx_tasks_lists`, `bx_tasks_contexts`, `bx_tasks_assignments`, `bx_tasks_pre_lists`, `bx_tasks_pre_values`, `bx_tasks_filters`, `bx_tasks_covers`, `bx_tasks_files`, `bx_tasks_photos`, `bx_tasks_photos_resized`, `bx_tasks_videos`, `bx_tasks_videos_resized`, `bx_tasks_cmts`, `bx_tasks_cmts_notes`, `bx_tasks_votes`, `bx_tasks_votes_track`, `bx_tasks_reactions`, `bx_tasks_reactions_track`, `bx_tasks_views_track`, `bx_tasks_meta_keywords`, `bx_tasks_meta_locations`, `bx_tasks_meta_mentions`, `bx_tasks_reports`, `bx_tasks_reports_track`, `bx_tasks_time`, `bx_tasks_time_track`, `bx_tasks_timers`, `bx_tasks_favorites_track`, `bx_tasks_scores`, `bx_tasks_scores_track`;
 
 -- STORAGES & TRANSCODERS
 DELETE FROM `sys_objects_storage` WHERE `object` LIKE 'bx_tasks_%';

+ 36 - 0
modules/boonex/tasks/js/pre_values.js

@@ -0,0 +1,36 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT 
+ * @defgroup    Tasks Tasks
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function BxTasksPreValues(oOptions)
+{
+    BxBaseModTextManageTools.call(this, oOptions);
+
+    this._sObjName = oOptions.sObjName == undefined ? 'oBxTasksPreValues' : oOptions.sObjName;
+}
+
+BxTasksPreValues.prototype = Object.create(BxBaseModTextManageTools.prototype);
+BxTasksPreValues.prototype.constructor = BxTasksPreValues;
+
+BxTasksPreValues.prototype.onChangeFilter = function(oFilter) {
+    var $this = this;
+    var oFilter1 = $('#bx-grid-filter1-' + this._sObjNameGrid);
+    var sValueFilter1 = oFilter1.length > 0 ? oFilter1.val() : '';
+
+    var oSearch = $('#bx-grid-search-' + this._sObjNameGrid);
+    var sValueSearch = oSearch.length > 0 ? oSearch.val() : '';
+    if(sValueSearch == _t('_sys_grid_search'))
+        sValueSearch = '';
+
+    clearTimeout($this._iSearchTimeoutId);
+    $this._iSearchTimeoutId = setTimeout(function () {
+        glGrids[$this._sObjNameGrid].setFilter(sValueFilter1 + $this._sParamsDivider + sValueSearch, true);
+    }, 500);
+};
+
+/** @} */

+ 2 - 0
modules/boonex/tasks/js/tasks.js

@@ -42,6 +42,8 @@ BxTasksView.prototype._setCompleted = function (iId, iValue, onComplete) {
 };
 
 BxTasksView.prototype.processContext = function (iContextId, obj) {
+    $('.bx-popup-applied:visible').dolPopupHide();
+
     var $this = this;
     $(window).dolPopupAjax({
         url: $this._oOptions.sActionUrl + 'process_context_form/' + iContextId + '/',

+ 2 - 2
modules/boonex/tasks/template/browse_tasks.html

@@ -13,8 +13,8 @@
             </a>
         </bx_if:allow_add_list>
         <bx_if:allow_manage_settings>
-            <a class="bx-btn bx-btn-small bx-def-margin-sec-right bx-tasks-tasklist-add" href="javascript:void(0);" onclick="__object__.processContext(__context_id__, this)">
-                <bx_text:_bx_tasks_txt_new_settings />
+            <a class="bx-btn bx-btn-small bx-def-margin-sec-right bx-tasks-tasklist-manage" href="javascript:void(0);" onclick="bx_menu_popup('bx_tasks_manage_context_submenu', this, {}, {context_pid: __context_id__});">
+                <bx_image_auto:cog />
             </a>
         </bx_if:allow_manage_settings>
     </span>

+ 5 - 0
modules/boonex/tasks/template/css/main.css

@@ -94,6 +94,11 @@
     width: 800px;
 }
 
+/*--- View Task ---*/
+.bx-tasks-stickers .bx-def-label {
+    color: #ffffff;
+}
+
 /*--- View Task: Comments List ---*/
 .cmts .cmt.cmt-auto {
     margin-bottom: 0.25rem;

+ 19 - 0
modules/boonex/tasks/template/popup_pre_values.html

@@ -0,0 +1,19 @@
+<div class="bx-tasks-pv-form">
+    <div class="bx-tasks-pv-form-cnt">
+        __form__
+        <script language="javascript">
+            $(document).ready(function () {
+                $("#__form_id__").ajaxForm({ 
+                    dataType: "json",
+                    beforeSubmit: function (formData, jqForm, options) {
+                        bx_loading($("#__form_id__"), true);
+                    },
+                    success: function (data) {
+                        $(".bx-popup-applied:visible").dolPopupHide();
+                        glGrids.__object__.processJson(data, '__action__');
+                    }
+                });
+            });
+        </script>
+    </div>
+</div>

+ 5 - 0
modules/boonex/tasks/template/stickers.html

@@ -0,0 +1,5 @@
+<div class="bx-tasks-stickers">
+    <bx_repeat:stickers>
+        <div class="bx-def-label" <bx_if:show_color>style="background-color:__color__"</bx_if:show_color>>__title__</div>
+    </bx_repeat:stickers>
+</div>