AntonLV 6 лет назад
Родитель
Сommit
7bd6e6d7e6

+ 29 - 0
form.php

@@ -0,0 +1,29 @@
+<?php
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+require_once('./inc/header.inc.php');
+require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");
+require_once(BX_DIRECTORY_PATH_INC . "utils.inc.php");
+
+bx_import('BxDolLanguages');
+
+$sObject = bx_process_input(bx_get('o'));
+$sDisplay = bx_process_input(bx_get('d'));
+$sAction = bx_process_input(bx_get('a'));
+if(!empty($sAction))
+    $sAction = 'performAction' . bx_gen_method_name($sAction);
+
+// try to create form object and call its method
+if(!empty($sObject) && !empty($sDisplay) && !empty($sAction)) {
+    $oForm = BxTemplFormView::getObjectInstance($sObject, $sDisplay);
+    if($oForm && method_exists($oForm, $sAction))
+        $oForm->$sAction();
+}
+
+/** @} */

+ 57 - 0
inc/classes/BxDolForm.php

@@ -732,6 +732,12 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
 
     protected $_aFieldsCheckForSpam = array(); ///< additional fields names to check for spam(profanity filter), now only fields with 'textarea' and 'text' are checked for spam, 'textarea' fields are checked for spam and filter for profanity, while 'text' fields are filtetered for profanity only
 
+    
+    protected $_iAuthorId;
+    protected $_sAuthorKey; ///< array key to get author ID from Values array provided in BxDolForm::initChecker.
+    protected $_sPrivacyObjectView;
+    protected $_sPrivacyGroupDefault;
+
     public function __construct ($aInfo, $oTemplate)
     {
         parent::__construct();
@@ -758,6 +764,10 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
 
         $this->_sChecker = isset($this->aParams['checker']) ? $this->aParams['checker'] : 'BxDolFormChecker';
         $this->_sCheckerHelper = isset($this->aParams['checker_helper']) ? $this->aParams['checker_helper'] : '';
+
+        $this->_sAuthorKey = 'author';
+        $this->_sPrivacyObjectView = 'sys_form_inputs_allow_view_to';
+        $this->_sPrivacyGroupDefault = BX_DOL_PG_ALL;
     }
 
     /**
@@ -825,6 +835,11 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
         if ($aValues)
             $oChecker->fillWithValues($this->aInputs, $aValues);
 
+        // init author from provided values if it's available
+
+        if (isset($aValues[$this->_sAuthorKey]))
+            $this->_iAuthorId = (int)$aValues[$this->_sAuthorKey];
+
 
         if ($this->isSubmitted ()) {
 
@@ -951,6 +966,17 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
         return $this->_aSpecificValues;
     }
 
+    function getAuthorId()
+    {
+        return $this->_iAuthorId;
+    }
+
+    function setAuthorId($iAuthorId)
+    {
+        $this->_iAuthorId = (int)$iAuthorId;
+        $this->aParams['params']['author_id'] = $this->_iAuthorId;
+    }
+
     public static function getSubmittedValue($sKey, $sMethod, &$aSpecificValues = false)
     {
         $aData = array();
@@ -1127,6 +1153,37 @@ class BxDolForm extends BxDol implements iBxDolReplaceable
         }
         return $s;
     }
+
+    protected function _getPrivacyIcon($mixedPrivacy)
+    {
+        switch($mixedPrivacy) {
+            case BX_DOL_PG_MEONLY:
+                $sResult = 'lock';
+                break;
+
+            case BX_DOL_PG_ALL:
+                $sResult = 'globe';
+                break;
+
+            default:
+                $sResult = 'user';
+                break;
+        }
+
+        return $sResult;
+    }
+    
+    protected function _getPrivacyGroup($sPrivacyObject, $iInputId, $iAuthorId = false)
+    {
+        if(!$iAuthorId)
+            $iAuthorId = bx_get_logged_profile_id();
+
+        $mixedPrivacyGroup = BxDolFormQuery::getInputPrivacy($iInputId, $iAuthorId, BxDolPrivacy::getFieldName($sPrivacyObject));
+        if(empty($mixedPrivacyGroup))
+            $mixedPrivacyGroup = $this->_sPrivacyGroupDefault;
+
+        return $mixedPrivacyGroup;
+    }
 }
 
 class BxDolFormChecker

+ 50 - 1
inc/classes/BxDolFormQuery.php

@@ -84,8 +84,9 @@ class BxDolFormQuery extends BxDolDb
                 'uri' => $aObject['uri'],
                 'uri_title' => $aObject['uri_title'],
             ),
-            'view_mode' => $aDisplay['view_mode'],
+            'object' => $sObject,
             'display' => $sDisplayName,
+            'view_mode' => $aDisplay['view_mode'],
         );
 
         $aForm['params'] = array_merge_recursive($aDefaultsFormParams, !empty($aAddFormParams) && is_array($aAddFormParams) ? $aAddFormParams : array());
@@ -99,6 +100,7 @@ class BxDolFormQuery extends BxDolDb
 
             // main attributes
             $aInput = array (
+                'id' => $a['id'],
                 'type' => $a['type'],
                 'name' => $a['name'],
                 'caption_system_src' => $a['caption_system'],
@@ -109,6 +111,7 @@ class BxDolFormQuery extends BxDolDb
                 'required' => $a['required'] ? true : false,
             	'unique' => $a['unique'] ? true : false,
                 'collapsed' => $a['collapsed'] ? true : false,
+                'privacy' => $a['privacy'] ? true : false,
                 'html' => $a['html'],
                 'attrs' => $a['attrs'] ? unserialize($a['attrs']) : false,
                 'tr_attrs' => $a['attrs_tr'] ? unserialize($a['attrs_tr']) : false,
@@ -216,6 +219,52 @@ class BxDolFormQuery extends BxDolDb
         ));
     }
 
+    static public function getInputByName($sObject, $sName)
+    {
+        return BxDolDb::getInstance()->getRow("SELECT * FROM `sys_form_inputs` WHERE `object`=:object AND `name`=:name LIMIT 1", array(
+            'object' => $sObject, 
+            'name' => $sName
+        ));
+    }
+
+    static public function getInputPrivacy($iInputId, $iAuthorId, $sPrivacyField = '')
+    {
+        $sMethod = 'getRow';
+        $sSelectClause = '*';
+
+        if(!empty($sPrivacyField)) {
+            $sMethod = 'getOne';
+            $sSelectClause = '`' . $sPrivacyField . '`';
+        }
+
+        return BxDolDb::getInstance()->$sMethod("SELECT " . $sSelectClause . " FROM `sys_form_inputs_privacy` WHERE `input_id`=:input_id AND `author_id`=:author_id LIMIT 1", array(
+            'input_id' => $iInputId,
+            'author_id' => $iAuthorId,
+        ));
+    }
+
+    static public function setInputPrivacy($iInputId, $iAuthorId, $sPrivacyField, $sPrivacyValue)
+    {
+        $oDb = BxDolDb::getInstance();
+
+        $sTable = 'sys_form_inputs_privacy';
+        $aBindingsSet = array(
+            $sPrivacyField => $sPrivacyValue
+        );
+        $aBindingsWhere = array(
+            'input_id' => $iInputId,
+            'author_id' => $iAuthorId,
+        );
+
+        $bResult = false;
+        if((int)$oDb->getOne("SELECT `id` FROM `" . $sTable . "` WHERE `input_id`=:input_id AND `author_id`=:author_id LIMIT 1", $aBindingsWhere) != 0)
+            $bResult = $oDb->query("UPDATE `" . $sTable . "` SET " . $oDb->arrayToSQL($aBindingsSet) . " WHERE " . $oDb->arrayToSQL($aBindingsWhere, ' AND ')) !== false;
+        else
+            $bResult = (int)$oDb->query("INSERT `" . $sTable . "` SET " . $oDb->arrayToSQL(array_merge($aBindingsSet, $aBindingsWhere))) > 0;
+
+        return $bResult;
+    }
+
     public function getFormInputs()
     {
         $sQuery = $this->prepare("SELECT * FROM `sys_form_inputs` WHERE `object` = ? ORDER BY `order` ASC", $this->_aObject['object']);

+ 60 - 0
inc/js/classes/BxDolForm.js

@@ -0,0 +1,60 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    UnaCore UNA Core
+ * @{
+ */
+
+function BxDolForm(oOptions)
+{
+    if(typeof oOptions === 'undefined')
+        return;
+
+    this._sObjName = oOptions.sObjName === undefined ? 'oForm' : oOptions.sObjName; // javascript object name, to run current object instance from onTimer
+    this._sObject = oOptions.sObject; // form object
+    this._sDisplay = oOptions.sDisplay; // form display
+
+    this._sActionsUri = 'form.php';
+    this._sActionsUrl = oOptions.sRootUrl + this._sActionsUri; // actions url address
+
+    this._sAnimationEffect = 'fade';
+    this._iAnimationSpeed = 'slow';
+    this._aHtmlIds = oOptions.aHtmlIds;
+}
+
+BxDolForm.prototype.pgcTogglePopup = function(oLink, iInputId, sPrivacyObject)
+{
+    var oData = this._getDefaultParams();
+    oData['a'] = 'get_privacy_group_chooser';
+    oData['input_id'] = iInputId;
+    oData['privacy_object'] = sPrivacyObject;
+
+    $(oLink).dolPopupAjax({
+        id: this._aHtmlIds['pgc_popup'] + iInputId, 
+        url: bx_append_url_params(this._sActionsUri, oData),
+        closeOnOuterClick: false,
+        removeOnClose: true,
+    });
+};
+
+BxDolForm.prototype.pgcOnSelectGroup = function(oData)
+{
+    if(oData && parseInt(oData.code) != 0)
+        return;
+
+    if(oData.form_id && oData.chooser_id && oData.icon)
+        $('#' + oData.form_id + ' #' + oData.chooser_id + ' .bx-form-input-pgc-current .sys-icon').removeClass().addClass('sys-icon ' + oData.icon);
+};
+
+BxDolForm.prototype._getDefaultParams = function() 
+{
+    var oDate = new Date();
+    return {
+        o: this._sObject,
+        d: this._sDisplay,
+        _t: oDate.getTime()
+    };
+};
+
+/** @} */

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
install/sql/system.sql


+ 10 - 2
modules/base/general/classes/BxBaseModGeneralFormsEntryHelper.php

@@ -135,6 +135,8 @@ class BxBaseModGeneralFormsEntryHelper extends BxDolProfileForms
 
     public function viewDataEntry ($iContentId)
     {
+        $CNF = &$this->_oModule->_oConfig->CNF;
+
         // get content data and profile info
         list ($oProfile, $aContentInfo) = $this->_getProfileAndContentData($iContentId);
         if (!$aContentInfo)
@@ -144,6 +146,12 @@ class BxBaseModGeneralFormsEntryHelper extends BxDolProfileForms
         if (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->_oModule->checkAllowedView($aContentInfo)))
             return MsgBox($sMsg);
 
+        $oForm = $this->getObjectFormView();
+        $oForm->initChecker($aContentInfo);
+
+        if(!empty($CNF['FIELD_TEXT']) &&  !$oForm->isInputVisible($CNF['FIELD_TEXT']))
+            return '';
+
         return $this->_oModule->_oTemplate->entryText($aContentInfo);
     }
 
@@ -439,11 +447,11 @@ class BxBaseModGeneralFormsEntryHelper extends BxDolProfileForms
         if ($sResult = $this->onDataDeleteAfter ($aContentInfo[$CNF['FIELD_ID']], $aContentInfo, $oProfile))
             return $sResult;
 
-		// create an alert
+        // create an alert
         bx_alert($this->_oModule->getName(), 'deleted', $aContentInfo[$CNF['FIELD_ID']], false, array(
             'content' => &$aContentInfo
         ));
-		
+
         return '';
     }
 

+ 2 - 0
modules/base/profile/classes/BxBaseModProfileFormEntry.php

@@ -21,6 +21,8 @@ class BxBaseModProfileFormEntry extends BxBaseModGeneralFormEntry
     {
         parent::__construct($aInfo, $oTemplate);
 
+        $this->_sAuthorKey = 'profile_id';
+
         $CNF = &$this->_oModule->_oConfig->CNF;
 
         if (!empty($CNF['FIELD_PICTURE']) && isset($this->aInputs[$CNF['FIELD_PICTURE']])) {

+ 5 - 0
modules/boonex/english/data/langs/system/en.xml

@@ -725,6 +725,7 @@
 	<string name="_adm_form_dsc_field_collapsed"><![CDATA[Pack down the group of this field by default]]></string>
 	<string name="_adm_form_dsc_field_html"><![CDATA[Select type of HTML editor]]></string>
 	<string name="_adm_form_dsc_field_info"><![CDATA[Enter field description (optional)]]></string>
+        <string name="_adm_form_dsc_field_privacy"><![CDATA[Check it if privacy settings can be changed for the field]]></string>
 	<string name="_adm_form_dsc_field_required"><![CDATA[Check it if the field should have value]]></string>
 	<string name="_adm_form_dsc_field_unique"><![CDATA[Check it if the field should have unique value]]></string>
 	<string name="_adm_form_dsc_field_value_button"><![CDATA[Enter button title here]]></string>
@@ -857,6 +858,7 @@
 	<string name="_adm_form_txt_field_module"><![CDATA[Module]]></string>
 	<string name="_adm_form_txt_field_name"><![CDATA[Name]]></string>
 	<string name="_adm_form_txt_field_object"><![CDATA[Form]]></string>
+        <string name="_adm_form_txt_field_privacy"><![CDATA[Privacy]]></string>
 	<string name="_adm_form_txt_field_required"><![CDATA[Mandatory]]></string>
 	<string name="_adm_form_txt_field_show_to_popup"><![CDATA[Show "{0}" form field to: ]]></string>
         <string name="_adm_form_txt_field_type_block_end"><![CDATA[block end]]></string>
@@ -1763,6 +1765,8 @@
   <string name="_sys_acl_action_switch_to_any_profile_desc"><![CDATA[Allow switch to any profile]]></string>
   <string name="_sys_acl_action_set_acl_as_privacy"><![CDATA[Choose membership level as privacy]]></string>
 	<string name="_sys_acl_action_set_acl_as_privacy_desc"><![CDATA[Choose membership level as privacy in add content forms]]></string>
+        <string name="_sys_acl_action_set_form_fields_privacy"><![CDATA[Set form fields privacy]]></string>
+	<string name="_sys_acl_action_set_form_fields_privacy_desc"><![CDATA[Allow to set privacy for form fields]]></string>
 	<string name="_sys_acl_action_suspended"><![CDATA[You can't '{1}' because your profile was suspended, if you don't know why - try to send message to <a href="mailto:{7}">administrator</a>.]]></string>
 	<string name="_sys_acl_action_unauthenticated"><![CDATA[Not logged in users can't '{1}'.]]></string>
 	<string name="_sys_acl_action_unconfirmed"><![CDATA[You didn't confirm your profile. Please check your email with profile activation link. Unconfirmed members can't <b>{1}</b>.]]></string>
@@ -2827,6 +2831,7 @@ If it is not enabled then please consider implement this optimization, since it
         <string name="_sys_profile_storage_quota_size"><![CDATA[Storage]]></string>
         <string name="_sys_profile_storage_quota_number"><![CDATA[Number of files]]></string>
 	<string name="_sys_private"><![CDATA[Private]]></string>
+        <string name="_sys_privacy_forms_input_allow_view_to"><![CDATA[Visibility]]></string>
         <string name="_sys_privacy_groups_acl"><![CDATA[Membership Levels]]></string>
     <string name="_sys_pruning_db"><![CDATA[<h3>Database pruning:</h3>
         <ul>

+ 5 - 0
modules/boonex/russian/data/langs/system/ru.xml

@@ -721,6 +721,7 @@
 	<string name="_adm_form_dsc_field_collapsed"><![CDATA[Упаковать группу данного поля по умолчанию]]></string>
 	<string name="_adm_form_dsc_field_html"><![CDATA[Выбрать тип HTML-редактора]]></string>
 	<string name="_adm_form_dsc_field_info"><![CDATA[Введите описание поля (необязательно)]]></string>
+        <string name="_adm_form_dsc_field_privacy"><![CDATA[Отметьте, если для данного поля настройки "Конфиденциальности" могут быть изменены]]></string>
 	<string name="_adm_form_dsc_field_required"><![CDATA[Отметьте, если поле должно иметь значение]]></string>
 	<string name="_adm_form_dsc_field_unique"><![CDATA[Отметьте, если поле должно иметь уникальное значение]]></string>
 	<string name="_adm_form_dsc_field_value_button"><![CDATA[Введите заголовок для кнопки]]></string>
@@ -853,6 +854,7 @@
 	<string name="_adm_form_txt_field_module"><![CDATA[Модуль]]></string>
 	<string name="_adm_form_txt_field_name"><![CDATA[Имя]]></string>
 	<string name="_adm_form_txt_field_object"><![CDATA[Форма]]></string>
+        <string name="_adm_form_txt_field_privacy"><![CDATA[Конфиденциальность]]></string>
 	<string name="_adm_form_txt_field_required"><![CDATA[Необходимое]]></string>
 	<string name="_adm_form_txt_field_show_to_popup"><![CDATA[Показывать "{0}" поле формы для: ]]></string>
         <string name="_adm_form_txt_field_type_block_end"><![CDATA[конец блока]]></string>
@@ -1750,6 +1752,8 @@
   <string name="_sys_acl_action_switch_to_any_profile_desc"><![CDATA[Разрешать переключаться на любой профиль]]></string>
         <string name="_sys_acl_action_set_acl_as_privacy"><![CDATA[Использовать уровень членства в настройках приватности]]></string>
 	<string name="_sys_acl_action_set_acl_as_privacy_desc"><![CDATA[Использовать уровень членства в настройках приватности в формах добавления контента]]></string>
+        <string name="_sys_acl_action_set_form_fields_privacy"><![CDATA[Назначение приватности для полей форм]]></string>
+	<string name="_sys_acl_action_set_form_fields_privacy_desc"><![CDATA[Разрешать менять приватность для полей форм]]></string>
 	<string name="_sys_acl_action_suspended"><![CDATA[Вы не можете '{1}', потому что Ваш профайл заблокирован. Если Вы не знаете, почему, постарайтесь связаться с <a href="mailto:{7}">администратором</a>.]]></string>
 	<string name="_sys_acl_action_unauthenticated"><![CDATA[Не вошедшие пользователи не могут '{1}'.]]></string>
 	<string name="_sys_acl_action_unconfirmed"><![CDATA[Вы не подтвердили свой профиль. Пожалуйста, проверьте эл. сообщение со ссылкой на активацию профиля. Неподтверждённые пользователи не могут <b>{1}</b>.]]></string>
@@ -2812,6 +2816,7 @@
     <string name="_sys_profile_storage_quota_size"><![CDATA[Хранилище]]></string>
         <string name="_sys_profile_storage_quota_number"><![CDATA[Количество файлов]]></string>
 	<string name="_sys_private"><![CDATA[Приватные]]></string>
+        <string name="_sys_privacy_forms_input_allow_view_to"><![CDATA[Видимость]]></string>
         <string name="_sys_privacy_groups_acl"><![CDATA[Членство]]></string>
     <string name="_sys_pruning_db"><![CDATA[<h3>Очистка базы данных:</h3>
         <ul>

+ 20 - 2
studio/template/scripts/BxBaseStudioFormsField.php

@@ -288,6 +288,10 @@ class BxBaseStudioFormsField extends BxDolStudioFormsField
                         $aForm['inputs'][$sKey]['checked'] = (int)$this->aField[$sKey];
                         break;
 
+                    case 'privacy':
+                        $aForm['inputs'][$sKey]['checked'] = (int)$this->aField[$sKey];
+                        break;
+
                     case 'checker_func':
                         $sCfValue = strtolower($this->aField[$sKey]);
                         $aForm['inputs'][$sKey]['value'] = $sCfValue;
@@ -981,6 +985,20 @@ class BxBaseStudioFormsFieldBlockHeader extends BxBaseStudioFormsField
                         'pass' => 'Int',
                     )
                 ),
+                'privacy' => array(
+                    'type' => 'switcher',
+                    'name' => 'privacy',
+                    'caption' => _t('_adm_form_txt_field_privacy'),
+                    'info' => _t('_adm_form_dsc_field_privacy'),
+                    'value' => '1',
+                    'required' => '0',
+                    'attrs' => array(
+                        'id' => 'bx-form-field-privacy'
+                    ),
+                    'db' => array (
+                        'pass' => 'Int',
+                    )
+                ),
                 'controls' => array(
                     'name' => 'controls',
                     'type' => 'input_set',
@@ -1116,8 +1134,8 @@ class BxBaseStudioFormsFieldValue extends BxBaseStudioFormsFieldBlockHeader
     protected $sType = 'value';
 
     public function init()
-	{
-		parent::init();
+    {
+        parent::init();
 
         $this->aForm['inputs']['caption']['info'] = _t('_adm_form_dsc_field_caption');
 

+ 28 - 0
template/css/forms.css

@@ -292,6 +292,34 @@
     z-index: 1;
 }
 
+/* privacy group chooser */
+.bx-form-input-wrapper-pgc {
+    position: relative;
+}
+
+.bx-form-input-pgc {
+    position: absolute;
+    display: -webkit-flex;
+    display: flex;
+    -webkit-align-items: center;
+    align-items: center;
+    -webkit-justify-content: center;
+    justify-content: center;
+    top: -1.375rem;
+    right: 0;
+    width: 1rem;
+    height: 1rem;
+}
+
+.bx-form-input-pgc-popup .bx-form-input-wrapper-input_set {
+    display: -webkit-flex;
+    display: flex;
+    -webkit-flex-wrap: nowrap;
+    flex-wrap: nowrap;
+    -webkit-align-items: center;
+    align-items: center;
+}
+
 /* switcher */
 
 .bx-switcher-cont {

+ 6 - 0
template/form_field_privacy.html

@@ -0,0 +1,6 @@
+<div id="__html_id__" class="bx-form-input-pgc">
+    <div class="bx-form-input-pgc-current">
+        <a class="bx-form-input-pgc-current" href="javascript:void(0)" onclick="javascript:__js_object__.pgcTogglePopup(this, __id__, '__privacy_object__')"><i class="sys-icon __icon__"></i></a>
+    </div>
+    <div id="__html_id_popup__"></div>
+</div>

+ 18 - 0
template/form_field_privacy_popup.html

@@ -0,0 +1,18 @@
+<div class="bx-form-input-pgc-popup">
+    __form__
+    <script type="text/javascript">
+        $(document).ready(function () {
+            $("#__form_id__").ajaxForm({ 
+                dataType: "json",
+                beforeSubmit: function(formData, jqForm, options) {
+                    bx_loading($("#__form_id__"), true);
+                },
+                success: function(oData) {
+                    $("#__form_id__").parents(".bx-popup-applied:visible:first").dolPopupHide();
+
+                    processJsonData(oData);
+                }
+            });
+        });
+    </script>
+</div>

+ 1 - 1
template/privacy_users_select_popup.html

@@ -9,7 +9,7 @@
                         bx_loading($("#__form_id__"), true);
                     },
                     success: function (oData) {
-                        $(".bx-popup-applied:visible").dolPopupHide();
+                        $("#__form_id__").parents(".bx-popup-applied:visible:first").dolPopupHide();
 
                         processJsonData(oData);
                     }

+ 248 - 4
template/scripts/BxBaseFormView.php

@@ -89,6 +89,11 @@ class BxBaseFormView extends BxDolForm
      * CSS files list for form
      */
     protected $_aCss = array();
+
+    protected $_sJsClassName;
+    protected $_sJsObjectName;
+    
+    protected $_aHtmlIds;
     
     /**
      * Constructor
@@ -112,6 +117,141 @@ class BxBaseFormView extends BxDolForm
             $this->_sSectionClose = 'getCloseSectionViewMode';
             $this->_sSectionOpen = 'getOpenSectionViewMode';
         }
+
+        $this->_sJsClassName = 'BxDolForm';
+
+        $sName = !empty($aInfo['params']['display']) ? $aInfo['params']['display'] : '';
+        if(empty($sName) && !empty($aInfo['params']['object']))
+            $sName = $aInfo['params']['object'];
+
+        $this->_sJsObjectName = 'oForm' . bx_gen_method_name($sName, array('_' , '-'));
+
+        $sHtmlId = str_replace(array('_' , ' '), array('-', '-'), $sName);
+        $this->_aHtmlIds = array(
+            'pgc' =>  $sHtmlId . '-pgc-',
+            'pgc_popup' => $sHtmlId . '-pgc-popup-',
+            'pgc_form' => $sHtmlId . '-pgc-form-',
+        );
+    }
+
+    public function performActionChangePrivacyGroup()
+    {
+        $iAuthorId = (int)bx_get_logged_profile_id();
+        if(empty($iAuthorId))
+            return echoJson(array());
+
+        $iInputId = bx_process_input(bx_get('input_id'), BX_DATA_INT);
+        if(empty($iInputId))
+            return echoJson(array());
+
+        $sPrivacyObject = bx_process_input(bx_get('privacy_object'));
+        $sPrivacyField = BxDolPrivacy::getFieldName($sPrivacyObject);
+        if(empty($sPrivacyField))
+            return echoJson(array());
+
+        $sPrivacyGroup = bx_process_input(bx_get($sPrivacyField));
+        if(empty($sPrivacyField))
+            return echoJson(array());
+
+        if(!BxDolFormQuery::setInputPrivacy($iInputId, $iAuthorId, $sPrivacyField, $sPrivacyGroup))
+            return echoJson(array());
+
+        return echoJson(array(
+            'code' => 0,
+            'form_id' => $this->getId(),
+            'chooser_id' => $this->_aHtmlIds['pgc'] . $iInputId,
+            'icon' => $this->_getPrivacyIcon($sPrivacyGroup),
+            'eval' => $this->getJsObjectName() . '.pgcOnSelectGroup(oData);'
+        ));
+    }
+
+    public function performActionGetPrivacyGroupChooser()
+    {
+        $iInputId = bx_process_input(bx_get('input_id'), BX_DATA_INT);
+        $sPrivacyObject = bx_process_input(bx_get('privacy_object'));
+        if(empty($iInputId) || empty($sPrivacyObject))
+            return '';
+
+        $sFormId = $this->_aHtmlIds['pgc_form'] . $iInputId;
+        $aFormActionParams = array();
+        if(!empty($this->aParams['object']) && !empty($this->aParams['display']))
+            $aFormActionParams = array(
+                'o' => $this->aParams['object'], 
+                'd' => $this->aParams['display']
+            );
+        $aFormActionParams['a'] = 'change_privacy_group';
+
+        $iAuthorId = bx_get_logged_profile_id();
+        $mixedPrivacyGroup = $this->_getPrivacyGroup($sPrivacyObject, $iInputId, $iAuthorId);
+
+        $oPrivacy = BxDolPrivacy::getObjectInstance($sPrivacyObject);
+        $aInputPgc = $oPrivacy->getGroupChooser($sPrivacyObject, $iAuthorId);
+        $aInputPgc['value'] = $mixedPrivacyGroup;
+
+        if(!isset($aInputPgc['content']))
+            $aInputPgc['content'] = '';
+        $aInputPgc['content'] .= $oPrivacy->addCssJs(true);
+        $aInputPgc['content'] .= $oPrivacy->initGroupChooser($sPrivacyObject, $iAuthorId, array(
+            'content_id' => $iInputId,
+            'group_id' => $mixedPrivacyGroup,
+            'html_ids' => array(
+                'form' => $sFormId
+            )
+        ));
+        
+        $aFormInfo = array(
+            'form_attrs' => array(
+                'id' => $sFormId,
+                'action' => BX_DOL_URL_ROOT . bx_append_url_params('form.php', $aFormActionParams),
+                'method' => 'post'
+            ),
+            'inputs' => array (
+                'input_id' => array(
+                    'type' => 'hidden',
+                    'name' => 'input_id',
+                    'value' => $iInputId,
+                    'db' => array (
+                        'pass' => 'Int',
+                    ),
+                ),
+                'privacy_object' => array(
+                    'type' => 'hidden',
+                    'name' => 'privacy_object',
+                    'value' => $sPrivacyObject,
+                    'db' => array (
+                        'pass' => 'Xss',
+                    ),
+                ),
+                'privacy_group_chooser' => $aInputPgc,
+                'controls' => array(
+                    'name' => 'controls',
+                    'type' => 'input_set',
+                    array(
+                        'type' => 'button',
+                        'name' => 'do_submit',
+                        'value' => _t('_sys_submit'),
+                        'attrs' => array(
+                            'onclick' => "$('#" . $sFormId . "').submit()",
+                        ),
+                    ),
+                    array (
+                        'type' => 'reset',
+                        'name' => 'do_cancel',
+                        'value' => _t('_Cancel'),
+                        'attrs' => array(
+                            'onclick' => "$(this).parents('.bx-popup-applied:visible:first').dolPopupHide()",
+                            'class' => 'bx-def-margin-sec-left',
+                        ),
+                    )
+                )
+            )
+        );
+        $oForm = new BxTemplFormView($aFormInfo);
+
+        echo $this->oTemplate->parseHtmlByName('form_field_privacy_popup.html', array(
+            'form_id' => $oForm->getId(),
+            'form' => $oForm->getCode(true),
+        ));
     }
 
     function setAjaxMode($bAjaxMode)
@@ -164,6 +304,34 @@ class BxBaseFormView extends BxDolForm
         return $sInclude . $sDynamicCssJs . $this->sCode;
     }
 
+    public function getJsClassName()
+    {
+        return $this->_sJsClassName;
+    }
+
+    public function getJsObjectName()
+    {
+        return $this->_sJsObjectName;
+    }
+
+    public function getJsScript()
+    {
+        $sJsObjName = $this->getJsObjectName();
+        $sJsObjClass = $this->getJsClassName();
+
+        $sCode = "if(window['" . $sJsObjName . "'] == undefined) var " . $sJsObjName . " = new " . $sJsObjClass . "(" . json_encode(array(
+            'sObjName' => $sJsObjName,
+            'sObject' => isset($this->aParams['object']) ? $this->aParams['object'] : '',
+            'sDisplay' => isset($this->aParams['display']) ? $this->aParams['display'] : '',
+            'sRootUrl' => BX_DOL_URL_ROOT,
+            'aHtmlIds' => array(
+                'pgc_popup' => 'bx-form-input-pgc-popup'
+            ),
+        )) . ");";
+
+        return $this->oTemplate->_wrapInTagJsCode($sCode);
+    }
+
     /**
      * Generate the whole form
      *
@@ -224,7 +392,7 @@ BLAH;
 BLAH;
         }
 
-        return $sForm;
+        return $this->getJsScript() . $sForm;
     }
 
     /**
@@ -361,6 +529,32 @@ BLAH;
         return $sRow;
     }
 
+    public function isInputVisible($mixedInput)
+    {
+        if(!is_array($mixedInput) && isset($this->aInputs[$mixedInput]))
+            $mixedInput = $this->aInputs[$mixedInput];
+
+        if(empty($mixedInput) || !is_array($mixedInput))
+            $mixedInput = BxDolFormQuery::getInputByName($this->aParams['object'], $mixedInput);
+
+        if(empty($mixedInput) || !is_array($mixedInput))
+            return false;
+
+        if(!empty($mixedInput['privacy']) && !empty($this->_iAuthorId)) {
+            $mixedResult = checkActionModule($this->_iAuthorId, 'set form fields privacy', 'system');
+            if($mixedResult[CHECK_ACTION_RESULT] === CHECK_ACTION_RESULT_ALLOWED) {
+                $aInputPrivacy = BxDolFormQuery::getInputPrivacy($mixedInput['id'], $this->_iAuthorId);
+                if(!empty($aInputPrivacy) && is_array($aInputPrivacy)) {
+                    $oPrivacy = BxDolPrivacy::getObjectInstance($this->_sPrivacyObjectView);            
+                    if($oPrivacy && !$oPrivacy->check($aInputPrivacy['id']))
+                        return false;
+                }
+            }
+        }
+
+        return true;
+    }
+
     /**
      * Generate single Table Row for view mode
      *
@@ -372,6 +566,9 @@ BLAH;
         if (!isset($aInput['type']))
             $aInput['type'] = false;
 
+        if(!$this->isInputVisible($aInput))
+            return '';
+
         if (!empty($aInput['name'])) {
             $sCustomMethod = 'genCustomRow' . $this->_genMethodName($aInput['name']);
             if (method_exists($this, $sCustomMethod))
@@ -600,9 +797,22 @@ EOS;
 
     function genWrapperInput($aInput, $sContent)
     {
-        $sAttr = isset($aInput['attrs_wrapper']) && is_array($aInput['attrs_wrapper']) ? bx_convert_array2attrs($aInput['attrs_wrapper']) : '';
+        $sClass = "bx-form-input-wrapper bx-form-input-wrapper-" . $aInput['type'];
+        if(isset($aInput['html']) && $aInput['html'] && $this->isHtmlEditor($aInput['html'], $aInput))
+            $sClass .= ' bx-form-input-wrapper-html';
+
+        $sAttrs = "";
+        if(isset($aInput['attrs_wrapper']) && is_array($aInput['attrs_wrapper'])) {
+            if(!empty($aInput['attrs_wrapper']['class'])) {
+                $sClass .= ' ' . trim($aInput['attrs_wrapper']['class']);
+
+                unset($aInput['attrs_wrapper']['class']);
+            }
 
-        return "<div class=\"bx-form-input-wrapper bx-form-input-wrapper-{$aInput['type']}" . ((isset($aInput['html']) && $aInput['html'] && $this->isHtmlEditor($aInput['html'], $aInput)) ? ' bx-form-input-wrapper-html' : '') . "\" $sAttr>$sContent</div>";
+            $sAttrs = bx_convert_array2attrs($aInput['attrs_wrapper']);
+        }
+
+        return "<div class=\"$sClass\" $sAttrs>$sContent</div>";
     }
 
     /**
@@ -815,6 +1025,9 @@ BLAH;
         // create input label
         $sInput .= $this->genLabel($aInput);
 
+        // create input privacy group chooser
+        $sInput .= $this->genPrivacyGroupChooser($aInput);
+
         return $sInput;
     }
 
@@ -1585,7 +1798,7 @@ BLAH;
      */
     function genLabel(&$aInput)
     {
-        if (!isset($aInput['label']) or empty($aInput['label']))
+        if (!isset($aInput['label']) || empty($aInput['label']))
             return '';
 
         $sInputID = $this->getInputId($aInput);
@@ -1593,6 +1806,36 @@ BLAH;
         return '<label for="' . $sInputID . '">' . bx_process_output($aInput['label']) . '</label>';
     }
 
+    function genPrivacyGroupChooser(&$aInput, $sPrivacyObject = '')
+    {
+        if(!isset($aInput['privacy']) || empty($aInput['privacy']))
+            return '';
+
+        $iAuthorId = bx_get_logged_profile_id();
+        $mixedResult = checkActionModule($iAuthorId, 'set form fields privacy', 'system');
+        if($mixedResult[CHECK_ACTION_RESULT] !== CHECK_ACTION_RESULT_ALLOWED)
+            return '';
+
+        if(empty($sPrivacyObject))
+            $sPrivacyObject = $this->_sPrivacyObjectView;
+
+        $iInputId = (int)$aInput['id'];
+        $mixedPrivacyGroup = $this->_getPrivacyGroup($sPrivacyObject, $iInputId, $iAuthorId);
+
+        if(!isset($aInput['attrs_wrapper']['class']))
+            $aInput['attrs_wrapper']['class'] = '';
+        $aInput['attrs_wrapper']['class'] .= ' bx-form-input-wrapper-pgc';
+
+        return $this->oTemplate->parseHtmlByName('form_field_privacy.html', array(
+            'js_object' => $this->getJsObjectName(),
+            'html_id' => $this->_aHtmlIds['pgc'] . $iInputId,
+            'html_id_popup' => $this->_aHtmlIds['pgc_popup'] . $iInputId,
+            'id' => $iInputId,
+            'privacy_object' => $sPrivacyObject,
+            'icon' => $this->_getPrivacyIcon($mixedPrivacyGroup)
+        ));
+    }
+
     function genInfoIcon($sInfo)
     {
         return '<div class="bx-form-info bx-def-font-grayed bx-def-font-small">' . bx_process_output($sInfo, BX_DATA_HTML) . '</div>';
@@ -1769,6 +2012,7 @@ BLAH;
 
         $this->_addCss('forms.css');
         $this->_addJs('jquery.webForms.js', "'undefined' === typeof($.fn.addWebForms)");
+        $this->_addJs('BxDolForm.js', "true");
 
         self::$_isCssJsAdded = true;
     }

Некоторые файлы не были показаны из-за большого количества измененных файлов