Просмотр исходного кода

#2990 Nested forms - general & persons & templates

RomanL 6 лет назад
Родитель
Сommit
09b6f2cd28

+ 43 - 0
modules/base/general/classes/BxBaseModGeneralDb.php

@@ -175,7 +175,50 @@ class BxBaseModGeneralDb extends BxDolModuleDb
 
         return $this->query("ALTER TABLE `" . $CNF['TABLE_ENTRIES'] . "` ADD FULLTEXT `" . $CNF['TABLE_ENTRIES_FULLTEXT'] . "` (" . trim($sFields, ', ') . ")");
     }
+    
+    public function deleteNestedById ($iNestedId, $sTableKey, $sTableName)
+	{
+		return $this->query("DELETE FROM `" . $sTableName . "` WHERE `" . $sTableKey . "` = :item_id", array('item_id' => $iNestedId));
+	}
+	
+	public function getNested ($iContentId, $sTableKey, $sTableName) 
+	{
+		return $this->getAllWithKey("SELECT `" . $sTableName . "`.* FROM `" . $sTableName . "` WHERE `item_id` = :item_id", $sTableKey, array('item_id' => $iContentId));
+	}
+   
+    function getNestedBy($aParams = array(), $sTableName)
+    {
+        $aMethod = array('name' => 'getAll', 'params' => array(0 => 'query', 1 => array()));
+        $sSelectClause = $sJoinClause = $sWhereClause = $sOrderClause = $sLimitClause = "";
+
+        $sSelectClause = "`" . $sTableName . "`.*";
+
+        switch($aParams['type']) {
+            case 'id':
+                $aMethod['name'] = 'getRow';
+                $aMethod['params'][1]['id'] = (int)$aParams['id'];
+
+                $sWhereClause .= " AND `" . $sTableName . "`.`" . $aParams['key_name'] . "` = :id";
+                break;
+                
+            case 'content_id':
+                $aMethod['name'] = 'getAllWithKey';
+                $aMethod['params'][2]['id'] = (int)$aParams['id'];
+                $aMethod['params'][1] = $aParams['key_name'];
+                $sWhereClause .= " AND `" . $sTableName . "`.`item_id` = :id";
+                break;
+        }
+
+        if(!empty($sOrderClause))
+            $sOrderClause = 'ORDER BY ' . $sOrderClause;
 
+        if(!empty($sLimitClause))
+            $sLimitClause = 'LIMIT ' . $sLimitClause;
+
+        $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $sTableName . "` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
+		return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
+    }
+    
     protected function _getEntriesBySearchIds($aParams, &$aMethod, &$sSelectClause, &$sJoinClause, &$sWhereClause, &$sOrderClause, &$sLimitClause)
     {
         $CNF = &$this->_oConfig->CNF;

+ 173 - 12
modules/base/general/classes/BxBaseModGeneralFormEntry.php

@@ -78,6 +78,12 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
         $aPrivacyFields = $this->_getPrivacyFields();
         foreach($aPrivacyFields as $sField => $sObject)
             $this->_preparePrivacyField($sField, $sObject);
+        
+        foreach($this->aInputs as $sKey => $aInput) {
+            if ($aInput['type'] == 'nested_form'){
+                $this->genGhostTemplateForInputNestedForm ($this->aInputs[$sKey]);
+            }
+        }
     }
 
     function getCode($bDynamicMode = false)
@@ -103,6 +109,128 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
         
         return $sResult;
     }
+    
+    /**
+     * Nested forms processing
+     */
+    function genInputNestedForm (&$aInput, $sInfo = '', $sError = '')
+    {
+        $sUniqId = genRndPwd (8, false);
+        
+        $aNestedForms = array();
+        if (!$this->isSubmitted()){
+            $aNestedValues = $this->_oModule->_oDb->getNestedBy(array('type' => 'content_id', 'id' => $this->_iContentId, 'key_name' => $aInput['ghost_template']['params']['db']['key']), $aInput['ghost_template']['params']['db']['table']);
+            foreach($aNestedValues as $aNestedValue) {
+                $aNestedValuesRv = array();
+                foreach($aNestedValue as $aNestedKey => $aNestedItem) {
+                    $aNestedValuesRv[$aNestedKey . '[]'] = $aNestedItem;
+                }
+                $oForm = $this->getNestedFormObject($aInput);  
+                $oForm->initChecker($aNestedValuesRv);
+                array_push(
+				    $aNestedForms,
+				    array(
+					    'key_value' => $aNestedValuesRv[$oForm->aParams['db']['key'] . '[]'],
+                        'key_name' => $aInput['name'],
+					    'form_code' => $oForm->genRows(),
+                        'js_instance_name' => 'oBxNestedForm_' . $sUniqId,
+                        'nested_type' => $aInput['name'],
+				    )
+			    );
+            }
+        }
+        else{
+            $aInput['ghost_templates'] = $aInput['ghost_template'];
+            $this->genGhostTemplateForInputNestedForm ($aInput);
+            foreach($aInput['ghost_templates'] as $oForm) {
+                array_push(
+				    $aNestedForms,
+				    array(
+					    'key_value' => $oForm->aInputs[$aInput['name']]['value'],
+                        'key_name' => $aInput['name'],
+					    'form_code' => $oForm->genRows(),
+                        'js_instance_name' => 'oBxNestedForm_' . $sUniqId,
+                        'nested_type' => $aInput['name'],
+				    )
+			    );
+            }
+        }
+
+        return $this->oTemplate->parseHtmlByName('form_field_nested_form.html', array(
+            'bx_repeat:items' => $aNestedForms,
+            'info' => $sInfo,
+            'error' => $sError,
+            'uniq_id' => $sUniqId,
+            'js_instance_name' => 'oBxNestedForm_' . $sUniqId,
+            'options' => json_encode(array(
+                'uniq_id' => $sUniqId,
+                'js_instance_name' => 'oBxNestedForm_' . $sUniqId,
+                'template_ghost' => $this->genGhostTemplate($aInput),
+                'form_name' => $aInput['value'],
+                'action_uri' =>  $this->_oModule->_oConfig->getBaseUri(),
+                'nested_type' => $aInput['name'],
+            )),
+        ));
+    }
+    
+    function genNestedForm (&$aInput)
+    {
+        $sResult = '';
+        $aNestedValues = $this->_oModule->_oDb->getNestedBy(array('type' => 'content_id', 'id' => $this->_iContentId, 'key_name' => $aInput['ghost_template']['params']['db']['key']), $aInput['ghost_template']['params']['db']['table']);
+        foreach($aNestedValues as $aNestedValue) {
+            $sValue = '';
+			$aNestedValuesRv = array();
+            foreach($aNestedValue as $aNestedKey => $aNestedItem) {
+                $aNestedValuesRv[$aNestedKey . '[]'] = $aNestedItem;
+            }
+            $oForm = $this->getNestedFormObject($aInput, true);  
+            $oForm->initChecker($aNestedValuesRv);
+            
+            if ($aInput['rateable']){
+                $sVotes = '';
+                $iId = BxDolFormQuery::getFormField($this->id, $aInput['name'], $this->_iContentId,  $aNestedValuesRv[$oForm->aParams['db']['key'] . '[]']);
+                $oVote = BxDolVote::getObjectInstance($aInput['rateable'], $iId, true, BxDolTemplate::getInstance());
+                if ($oVote)    
+                    $sVotes = $oVote->getElementInline(array('show_counter_empty' => true, 'show_counter' => true, 'show_counter_style' => 'compound', 'dynamic_mode' => $this->_bDynamicMode));
+				$sValue = $this->oTemplate->parseHtmlByName('form_view_rateable_row.html', array(
+					'value' =>  $oForm->getCode(),
+					'rate' => $sVotes
+				));
+            }
+			else{
+				$sValue =  $oForm->getCode();
+			}
+			$sResult .= $this->oTemplate->parseHtmlByName('form_view_nested_row.html', array(
+				'value' =>  $sValue
+			));
+        }
+        return $this->oTemplate->parseHtmlByName('form_view_row.html', array(
+            'type' => $aInput['type'], 
+            'caption' => isset($aInput['caption']) ? bx_process_output($aInput['caption']) : '',
+            'value' => $sResult
+        ));
+    }
+    
+    protected function genGhostTemplateForInputNestedForm (&$aInput)
+    {
+        $oForm = $this->getNestedFormObject($aInput);  
+        $aInput['ghost_template'] = array ( 
+            'params' => array(
+                'nested_form_template' => 'form_field_nested_form_wrapper.html',
+                'db' => array(
+                    'table' => $oForm->aParams['db']['table'],
+                    'key' => $oForm->aParams['db']['key'],
+                    'submit_name' =>  $oForm->aParams['db']['key'],
+                ),
+            ),
+            'inputs' => $oForm->aInputs
+        );
+    }
+    
+    function getNestedFormObject (&$aInput, $bViewMode = false)
+    {
+        return BxDolForm::getObjectInstance($aInput['value'], $aInput['value'] . ($bViewMode ? '_view' : ''));
+    }
 
     /**
      * Add field(s) which will be tracked during content update. 
@@ -253,13 +381,26 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
         $iContentId = parent::insert ($aValsToAdd, $isIgnore);
         
         if(!empty($iContentId)){
+            foreach($this->aInputs as $aInput) {
+                if ($aInput['type'] == 'nested_form'){
+			        if (is_array($aInput['ghost_template']) && !isset($aInput['ghost_template']['inputs'])) {
+				        foreach ($aInput['ghost_template'] as $oFormNested) {
+					        $iNestedContentId = $oFormNested->insert(array('item_id' => $iContentId));
+                            if ($aInput['rateable']){
+                                BxDolFormQuery::addFormField($this->id, $aInput['name'], $iContentId, $aValsToAdd[$CNF['FIELD_AUTHOR']], $this->_oModule->getName(), $iNestedContentId);
+                            }
+				        }
+			        }
+                }
+		    }
+            
             if ($bMulticatEnabled)
                 $this->processMulticatAfter($CNF['FIELD_MULTICAT'], $iContentId);
         }
         
         
         foreach($this->aInputs as $aInput) {
-            if ($aInput['rateable']){
+            if ($aInput['rateable'] && $aInput['type'] != 'nested_form'){
                 BxDolFormQuery::addFormField($this->id, $aInput['name'], $iContentId, $aValsToAdd[$CNF['FIELD_AUTHOR']], $this->_oModule->getName());
             }
         }
@@ -298,6 +439,25 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
         
         $mixedResult = parent::update($iContentId, $aValsToAdd, $aTrackTextFieldsChanges);
         
+        foreach($this->aInputs as $aInput) {
+            if ($aInput['type'] == 'nested_form'){
+                if (is_array($aInput['ghost_template']) && !isset($aInput['ghost_template']['inputs'])) {
+                    foreach ($aInput['ghost_template'] as $oFormNested) {
+                        $iNestedContentId = $oFormNested->aInputs[$aInput['name']]['value'];
+                        if (empty($iNestedContentId)){
+                            $iNestedContentId = $oFormNested->insert(array('item_id' => $iContentId));
+                            if ($aInput['rateable']){
+                                BxDolFormQuery::addFormField($this->id, $aInput['name'], $iContentId, $aContentInfo[$CNF['FIELD_AUTHOR']], $this->_oModule->getName(), $iNestedContentId);
+                            }
+                        }
+                        else{
+                            $oFormNested->update($iNestedContentId, array('item_id' => $iContentId));
+                        }
+                    }
+                }
+            }
+        }
+        
         if ($bMulticatEnabled)
             $this->processMulticatAfter($CNF['FIELD_MULTICAT'], $iContentId);
         
@@ -460,8 +620,9 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
     
     function genViewRowWrapped(&$aInput)
     {
+        $sResult =  parent::genViewRowWrapped($aInput);
         if (!$aInput['rateable']){
-            return parent::genViewRowWrapped($aInput);
+            return $sResult;
         }
         
         $sValue = $this->genViewRowValue($aInput);
@@ -470,16 +631,16 @@ class BxBaseModGeneralFormEntry extends BxTemplFormView
         
         // process rateable fields
         $iId = BxDolFormQuery::getFormField($this->id, $aInput['name'], $this->_iContentId);
-        $sReactions = '';
-        $oReaction = BxDolVote::getObjectInstance($aInput['rateable'], $iId, true, BxDolTemplate::getInstance());
-        if ($oReaction)    
-            $sReactions = $oReaction->getElementInline(array('show_counter_empty' => true, 'show_counter' => true, 'show_counter_style' => 'simple', 'dynamic_mode' => $this->_bDynamicMode));
-        
-        return $this->oTemplate->parseHtmlByName('form_view_row.html', array(
-            'type' => $aInput['type'], 
-            'caption' => isset($aInput['caption']) ? bx_process_output($aInput['caption']) : '',
-            'value' => $sValue . $sReactions
-        ));
+        $sVote = '';
+        $oVote = BxDolVote::getObjectInstance($aInput['rateable'], $iId, true, BxDolTemplate::getInstance());
+        if ($oVote){
+            $sVote = $oVote->getElementInline(array('show_counter_empty' => true, 'show_counter' => true, 'show_counter_style' => 'compound', 'dynamic_mode' => $this->_bDynamicMode));
+			return $this->oTemplate->parseHtmlByName('form_view_rateable_row.html', array(
+				'value' => $sResult,
+				'rate' => $sVote
+			));
+        }
+		return $sResult;
     }
 
     function setMetatagsKeywordsData($iId, $a, $o)

+ 46 - 0
modules/base/general/classes/BxBaseModGeneralModule.php

@@ -85,6 +85,52 @@ class BxBaseModGeneralModule extends BxDolModule
 
         echo $aCmtsNotes['content'];
     }
+    
+    public function actionNested()
+    {
+        $sAction = bx_get('a');
+        $sMethodName = 'subaction' . ucfirst($sAction);
+        if (!method_exists($this, $sMethodName)) {
+            return;
+        }
+        $this->$sMethodName();
+    }
+   
+	public function subactionDelete()
+    {
+        header('Content-type: text/html; charset=utf-8');
+
+        $iNestedId = (int)bx_get('id');
+		$sNestedForm = bx_get('s');
+        
+        $oForm = BxDolForm::getObjectInstance($sNestedForm, $sNestedForm);
+        if (!$oForm){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+
+        $aNested = $this->_oDb->getNestedBy(array('type' => 'id', 'id' => $iNestedId, 'key_name' => $oForm->aParams['db']['key']), $oForm->aParams['db']['table']);
+        if (empty($aNested)){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+        
+        $aContentInfo = $this->_oDb->getContentInfoById ($aNested['item_id']); 
+        if (!$aContentInfo){
+            echo _t('_sys_request_page_not_found_cpt');
+            return;
+        }
+
+        elseif (CHECK_ACTION_RESULT_ALLOWED !== ($sMsg = $this->checkAllowedEdit ($aContentInfo))) {
+            echo $sMsg;
+        } 
+        elseif (!$this->_oDb->deleteNestedById($iNestedId, $oForm->aParams['db']['key'], $oForm->aParams['db']['table'])) {
+            echo _t('_sys_txt_error_occured');
+        } 
+        else {
+            echo 'ok';
+        }
+    }
 
     // ====== SERVICE METHODS
     

+ 4 - 0
modules/boonex/decorous/data/template/studio/scripts/BxTemplStudioFormsField.php

@@ -41,6 +41,10 @@ class BxTemplStudioFormsFieldNumber extends BxBaseStudioFormsFieldNumber
 {
 }
 
+class BxTemplStudioFormsFieldNestedForm extends BxBaseStudioFormsFieldNestedForm
+{
+}
+
 class BxTemplStudioFormsFieldTime extends BxBaseStudioFormsFieldTime
 {
 }

+ 6 - 1
modules/boonex/english/data/langs/system/en.xml

@@ -758,6 +758,7 @@
 	<string name="_adm_form_err_field_add"><![CDATA[Cannot add new field]]></string>
         <string name="_adm_form_err_field_add_already_exists"><![CDATA[Field with similar name already exists]]></string>
 	<string name="_adm_form_err_field_add_not_allowed"><![CDATA[Fields cannot be added in this form]]></string>
+  <string name="_adm_form_err_field_select_nested_form"><![CDATA[Nested form must be selected.]]></string>
 	<string name="_adm_form_err_field_caption"><![CDATA[A name with at least 3 characters is required.]]></string>
         <string name="_adm_form_err_field_caption_system"><![CDATA[A name with at least 3 characters is required.]]></string>
 	<string name="_adm_form_err_field_checker_error"><![CDATA[You need to enter error message]]></string>
@@ -877,6 +878,7 @@
   <string name="_adm_form_txt_field_rateable_value_votes"><![CDATA[Use votes]]></string>
   <string name="_adm_form_txt_field_rateable_value_reactions"><![CDATA[Use reactions]]></string>
   <string name="_adm_form_txt_field_required"><![CDATA[Mandatory]]></string>
+  <string name="_adm_form_txt_field_select_nested_form"><![CDATA[Select nested form]]></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>
 	<string name="_adm_form_txt_field_type_block_header"><![CDATA[block header]]></string>
@@ -914,7 +916,8 @@
 	<string name="_adm_form_txt_field_type_textarea"><![CDATA[textarea]]></string>
         <string name="_adm_form_txt_field_type_time"><![CDATA[time]]></string>
 	<string name="_adm_form_txt_field_type_value"><![CDATA[info]]></string>
-	<string name="_adm_form_txt_field_unique"><![CDATA[Unique]]></string>
+  <string name="_adm_form_txt_field_type_nested_form"><![CDATA[nested form]]></string>
+  <string name="_adm_form_txt_field_unique"><![CDATA[Unique]]></string>
 	<string name="_adm_form_txt_field_value_button"><![CDATA[Title]]></string>
 	<string name="_adm_form_txt_field_value_checkbox"><![CDATA[Value]]></string>
 	<string name="_adm_form_txt_field_value_custom_text"><![CDATA[Custom text]]></string>
@@ -2229,6 +2232,8 @@ If it is not enabled then please consider implement this optimization, since it
 	<string name="_sys_form_input_sys_location"><![CDATA[Location]]></string>
 	<string name="_sys_form_input_location"><![CDATA[Location]]></string>
         <string name="_sys_form_input_location_radius_label"><![CDATA[Radius (in km)]]></string>
+  <string name="_sys_form_input_nested_form_button_add_new_item"><![CDATA[Add new item]]></string>
+  <string name="_sys_form_input_nested_form_button_delete_item"><![CDATA[Delete item]]></string>
 	<string name="_sys_form_input_sys_anonymous"><![CDATA[Post as anonymous]]></string>
 	<string name="_sys_form_input_anonymous"><![CDATA[Post as anonymous]]></string>
         <string name="_sys_form_input_sys_labels"><![CDATA[Labels]]></string>

+ 4 - 0
modules/boonex/lucid/data/template/studio/scripts/BxTemplStudioFormsField.php

@@ -41,6 +41,10 @@ class BxTemplStudioFormsFieldNumber extends BxBaseStudioFormsFieldNumber
 {
 }
 
+class BxTemplStudioFormsFieldNestedForm extends BxBaseStudioFormsFieldNestedForm
+{
+}
+
 class BxTemplStudioFormsFieldTime extends BxBaseStudioFormsFieldTime
 {
 }

+ 4 - 0
modules/boonex/ocean/data/template/studio/scripts/BxTemplStudioFormsField.php

@@ -41,6 +41,10 @@ class BxTemplStudioFormsFieldNumber extends BxBaseStudioFormsFieldNumber
 {
 }
 
+class BxTemplStudioFormsFieldNestedForm extends BxBaseStudioFormsFieldNestedForm
+{
+}
+
 class BxTemplStudioFormsFieldTime extends BxBaseStudioFormsFieldTime
 {
 }

+ 9 - 0
modules/boonex/persons/install/langs/en.xml

@@ -61,6 +61,8 @@
     <string name="_bx_persons_form_profile_input_profile_status"><![CDATA[Status]]></string>
     <string name="_bx_persons_form_profile_input_sys_profile_ip"><![CDATA[IP]]></string>
     <string name="_bx_persons_form_profile_input_profile_ip"><![CDATA[IP]]></string>
+    <string name="_bx_persons_form_profile_input_sys_skills"><![CDATA[Skills]]></string>
+    <string name="_bx_persons_form_profile_input_skills"><![CDATA[Skills]]></string>
     <string name="_bx_persons_form_profile_input_sys_date_added"><![CDATA[Added]]></string>
     <string name="_bx_persons_form_profile_input_date_added"><![CDATA[Added]]></string>
     <string name="_bx_persons_form_profile_input_sys_date_changed"><![CDATA[Updated]]></string>
@@ -70,6 +72,13 @@
     <string name="_bx_persons_form_profile_input_sys_followers_count"><![CDATA[Followers count]]></string>
     <string name="_bx_persons_form_profile_input_followers_count"><![CDATA[Followers count]]></string>
 
+  <string name="_bx_persons_skills_form_profile"><![CDATA[Skills]]></string>
+  <string name="_bx_persons_skills_form_profile_display_add"><![CDATA[Add Skill]]></string>
+  <string name="_bx_persons_skills_form_profile_display_view"><![CDATA[View Skill]]></string>
+  <string name="_bx_persons_skills_form_profile_input_sys_name"><![CDATA[Name]]></string>
+  <string name="_bx_persons_skills_form_profile_input_name"><![CDATA[Name]]></string>
+  <string name="_bx_persons_skills_form_profile_input_name_err"><![CDATA[This information is essential. Please, fill in this field.]]></string>
+
 	<string name="_bx_persons_acl_action_create_profile"><![CDATA[Create Person's Profile]]></string>
 	<string name="_bx_persons_acl_action_delete_profile"><![CDATA[Delete Person's Profile]]></string>
 	<string name="_bx_persons_acl_action_view_profile"><![CDATA[View Person's Profile]]></string>

+ 42 - 27
modules/boonex/persons/install/sql/install.sql

@@ -205,6 +205,14 @@ CREATE TABLE IF NOT EXISTS `bx_persons_scores_track` (
   KEY `vote` (`object_id`, `author_nip`)
 );
 
+CREATE TABLE `bx_persons_skills` (
+  `skill_id` int(11) NOT NULL AUTO_INCREMENT,
+  `skill_name` varchar(500) DEFAULT NULL,
+  `content_id` int(11) NOT NULL,
+  PRIMARY KEY (`skill_id`),
+  KEY `content_id` (`content_id`)
+);
+
 
 -- STORAGES & TRANSCODERS
 INSERT INTO `sys_objects_storage` (`object`, `engine`, `params`, `token_life`, `cache_control`, `levels`, `table_files`, `ext_mode`, `ext_allow`, `ext_deny`, `quota_size`, `current_size`, `quota_number`, `current_number`, `max_file_size`, `ts`) VALUES
@@ -232,8 +240,9 @@ INSERT INTO `sys_transcoder_filters` (`transcoder_object`, `filter`, `filter_par
 ('bx_persons_gallery', 'Resize', 'a:1:{s:1:"w";s:3:"500";}', '0');
 
 -- FORMS
-INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
-('bx_person', 'bx_persons', '_bx_persons_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_persons_data', 'id', '', '', 'do_submit', '', 0, 1, 'BxPersonsFormEntry', 'modules/boonex/persons/classes/BxPersonsFormEntry.php');
+INSERT INTO `sys_objects_form`(`object`, `module`, `title`, `action`, `form_attrs`, `table`, `key`, `uri`, `uri_title`, `submit_name`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`, `parent_form`) VALUES 
+('bx_person', 'bx_persons', '_bx_persons_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_persons_data', 'id', '', '', 'do_submit', '', 0, 1, 'BxPersonsFormEntry', 'modules/boonex/persons/classes/BxPersonsFormEntry.php', ''),
+('bx_person_skills', 'bx_persons', '_bx_persons_skills_form_profile', '', 'a:1:{s:7:\"enctype\";s:19:\"multipart/form-data\";}', 'bx_persons_skills', 'skills', '', '', 'do_submit', '', 0, 1, '', '', 'bx_person');
 
 INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`, `title`) VALUES 
 ('bx_person', 'bx_person_add', 'bx_persons', 0, '_bx_persons_form_profile_display_add'),
@@ -241,30 +250,33 @@ INSERT INTO `sys_form_displays`(`object`, `display_name`, `module`, `view_mode`,
 ('bx_person', 'bx_person_edit', 'bx_persons', 0, '_bx_persons_form_profile_display_edit'),
 ('bx_person', 'bx_person_edit_cover', 'bx_persons', 0, '_bx_persons_form_profile_display_edit_cover'),
 ('bx_person', 'bx_person_view', 'bx_persons', 1, '_bx_persons_form_profile_display_view'),
-('bx_person', 'bx_person_view_full', 'bx_persons', 1, '_bx_persons_form_profile_display_view_full');
-
-INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`) VALUES 
-('bx_person', 'bx_persons', 'allow_view_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_view_to', '_bx_persons_form_profile_input_allow_view_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'allow_post_to', 5, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_post_to', '_bx_persons_form_profile_input_allow_post_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'allow_contact_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_contact_to', '_bx_persons_form_profile_input_allow_contact_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_persons_form_profile_input_sys_delete_confirm', '_bx_persons_form_profile_input_delete_confirm', '_bx_persons_form_profile_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_form_profile_input_delete_confirm_error', '', '', 1, 0),
-('bx_person', 'bx_persons', 'do_submit', '_bx_persons_form_profile_input_submit', '', 0, 'submit', '_bx_persons_form_profile_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'description', '', '', 0, 'textarea', '_bx_persons_form_profile_input_sys_desc', '_bx_persons_form_profile_input_desc', '', 0, 0, 1, '', '', '', '', '', '', 'XssHtml', '', 1, 1),
-('bx_person', 'bx_persons', 'fullname', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_fullname', '_bx_persons_form_profile_input_fullname', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_form_profile_input_fullname_err', 'Xss', '', 1, 0),
-('bx_person', 'bx_persons', 'cover', 'a:1:{i:0;s:21:"bx_persons_cover_crop";}', 'a:1:{s:21:"bx_persons_cover_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_cover', '_bx_persons_form_profile_input_cover', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'picture', 'a:1:{i:0;s:23:"bx_persons_picture_crop";}', 'a:1:{s:23:"bx_persons_picture_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_picture', '_bx_persons_form_profile_input_picture', '', 0, 0, 0, '', '', '', '', '', '_bx_persons_form_profile_input_picture_err', '', '', 1, 0),
-('bx_person', 'bx_persons', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'birthday', '0', '', 0, 'datepicker', '_bx_persons_form_profile_input_sys_birthday', '_bx_persons_form_profile_input_birthday', '', 1, 0, 0, '', '', '', 'date_range', 'a:3:{s:3:"min";i:18;s:3:"max";i:99;s:8:"required";b:0;}', '_bx_persons_form_profile_input_birthday_err', 'Date', '', 1, 0),
-('bx_person', 'bx_persons', 'gender', '', '#!Sex', 0, 'select', '_bx_persons_form_profile_input_sys_gender', '_bx_persons_form_profile_input_gender', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0),
-('bx_person', 'bx_persons', 'profile_email', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_email', '_bx_persons_form_profile_input_profile_email', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
-('bx_person', 'bx_persons', 'profile_status', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_status', '_bx_persons_form_profile_input_profile_status', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
-('bx_person', 'bx_persons', 'profile_ip', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_ip', '_bx_persons_form_profile_input_profile_ip', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0),
-('bx_person', 'bx_persons', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'added', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_added', '_bx_persons_form_profile_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'changed', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_changed', '_bx_persons_form_profile_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'friends_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_friends_count', '_bx_persons_form_profile_input_friends_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
-('bx_person', 'bx_persons', 'followers_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_followers_count', '_bx_persons_form_profile_input_followers_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0);
-
+('bx_person', 'bx_person_view_full', 'bx_persons', 1, '_bx_persons_form_profile_display_view_full'),
+('bx_person_skills', 'bx_person_skills', 'bx_persons', 0, '_bx_persons_skills_form_profile_display_add'),
+('bx_person_skills', 'bx_person_skills_view', 'bx_persons', 1, '_bx_persons_skills_form_profile_display_view');
+
+INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `checked`, `type`, `caption_system`, `caption`, `info`, `required`, `collapsed`, `html`, `attrs`, `attrs_tr`, `attrs_wrapper`, `checker_func`, `checker_params`, `checker_error`, `db_pass`, `db_params`, `editable`, `deletable`, `rateable`) VALUES 
+('bx_person', 'bx_persons', 'allow_view_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_view_to', '_bx_persons_form_profile_input_allow_view_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'allow_post_to', 5, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_post_to', '_bx_persons_form_profile_input_allow_post_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'allow_contact_to', 3, '', 0, 'custom', '_bx_persons_form_profile_input_sys_allow_contact_to', '_bx_persons_form_profile_input_allow_contact_to', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'delete_confirm', 1, '', 0, 'checkbox', '_bx_persons_form_profile_input_sys_delete_confirm', '_bx_persons_form_profile_input_delete_confirm', '_bx_persons_form_profile_input_delete_confirm_info', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_form_profile_input_delete_confirm_error', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'do_submit', '_bx_persons_form_profile_input_submit', '', 0, 'submit', '_bx_persons_form_profile_input_sys_do_submit', '', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'description', '', '', 0, 'textarea', '_bx_persons_form_profile_input_sys_desc', '_bx_persons_form_profile_input_desc', '', 0, 0, 1, '', '', '', '', '', '', 'XssHtml', '', 1, 1, ''),
+('bx_person', 'bx_persons', 'fullname', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_fullname', '_bx_persons_form_profile_input_fullname', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_form_profile_input_fullname_err', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'cover', 'a:1:{i:0;s:21:"bx_persons_cover_crop";}', 'a:1:{s:21:"bx_persons_cover_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_cover', '_bx_persons_form_profile_input_cover', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'picture', 'a:1:{i:0;s:23:"bx_persons_picture_crop";}', 'a:1:{s:23:"bx_persons_picture_crop";s:24:"_sys_uploader_crop_title";}', 0, 'files', '_bx_persons_form_profile_input_sys_picture', '_bx_persons_form_profile_input_picture', '', 0, 0, 0, '', '', '', '', '', '_bx_persons_form_profile_input_picture_err', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'location', '', '', 0, 'location', '_sys_form_input_sys_location', '_sys_form_input_location', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'birthday', '0', '', 0, 'datepicker', '_bx_persons_form_profile_input_sys_birthday', '_bx_persons_form_profile_input_birthday', '', 1, 0, 0, '', '', '', 'date_range', 'a:3:{s:3:"min";i:18;s:3:"max";i:99;s:8:"required";b:0;}', '_bx_persons_form_profile_input_birthday_err', 'Date', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'gender', '', '#!Sex', 0, 'select', '_bx_persons_form_profile_input_sys_gender', '_bx_persons_form_profile_input_gender', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'profile_email', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_email', '_bx_persons_form_profile_input_profile_email', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'profile_status', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_status', '_bx_persons_form_profile_input_profile_status', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'profile_ip', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_profile_ip', '_bx_persons_form_profile_input_profile_ip', '', 0, 0, 0, '', '', '', '', '', '', 'Xss', '', 0, 0, ''),
+('bx_person', 'bx_persons', 'labels', '', '', 0, 'custom', '_sys_form_input_sys_labels', '_sys_form_input_labels', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'skills', 'bx_person_skills', '', 0, 'nested_form', '_bx_persons_form_profile_input_sys_skills', '_bx_persons_form_profile_input_skills', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, 'sys_form_fields_votes'),
+('bx_person', 'bx_persons', 'added', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_added', '_bx_persons_form_profile_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'changed', '', '', 0, 'datetime', '_bx_persons_form_profile_input_sys_date_changed', '_bx_persons_form_profile_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'friends_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_friends_count', '_bx_persons_form_profile_input_friends_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, ''),
+('bx_person', 'bx_persons', 'followers_count', '', '', 0, 'text', '_bx_persons_form_profile_input_sys_followers_count', '_bx_persons_form_profile_input_followers_count', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0, '');
+('bx_person_skills', 'bx_persons', 'skill_name[]', '', '', 0, 'text', '_bx_persons_skills_form_profile_input_sys_skill_name', '_bx_persons_skills_form_profile_input_name', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_persons_skills_form_profile_input_name_err', 'Xss', '', 1, 0, '', '');
 
 INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
 ('bx_person_add', 'picture', 2147483647, 1, 1),
@@ -317,7 +329,10 @@ INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for
 ('bx_person_view_full', 'fullname', 2147483647, 1, 3),
 ('bx_person_view_full', 'description', 2147483647, 0, 4),
 ('bx_person_view_full', 'profile_email', 192, 1, 5),
-('bx_person_view_full', 'profile_status', 192, 1, 6);
+('bx_person_view_full', 'profile_status', 192, 1, 6),
+
+('bx_person_skills', 'name', 2147483647, 1, 1),
+('bx_person_skills_view', 'name', 2147483647, 1, 1);
 
 -- COMMENTS
 INSERT INTO `sys_objects_cmts` (`Name`, `Module`, `Table`, `CharsPostMin`, `CharsPostMax`, `CharsDisplayMax`, `Html`, `PerView`, `PerViewReplies`, `BrowseType`, `IsBrowseSwitch`, `PostFormPosition`, `NumberOfLevels`, `IsDisplaySwitch`, `IsRatable`, `ViewingThreshold`, `IsOn`, `RootStylePrefix`, `BaseUrl`, `ObjectVote`, `TriggerTable`, `TriggerFieldId`, `TriggerFieldAuthor`, `TriggerFieldTitle`, `TriggerFieldComments`, `ClassName`, `ClassFile`) VALUES

+ 2 - 2
modules/boonex/persons/install/sql/uninstall.sql

@@ -1,6 +1,6 @@
 
 -- TABLES
-DROP TABLE IF EXISTS `bx_persons_data`,`bx_persons_pictures`, `bx_persons_pictures_resized`, `bx_persons_cmts`, `bx_persons_cmts_notes`, `bx_persons_views_track`, `bx_persons_votes`, `bx_persons_votes_track`, `bx_persons_favorites_track`, `bx_persons_reports`, `bx_persons_reports_track`, `bx_persons_meta_keywords`, `bx_persons_meta_locations`, `bx_persons_meta_mentions`, `bx_persons_scores`, `bx_persons_scores_track`;
+DROP TABLE IF EXISTS `bx_persons_data`,`bx_persons_pictures`, `bx_persons_pictures_resized`, `bx_persons_cmts`, `bx_persons_cmts_notes`, `bx_persons_views_track`, `bx_persons_votes`, `bx_persons_votes_track`, `bx_persons_favorites_track`, `bx_persons_reports`, `bx_persons_reports_track`, `bx_persons_meta_keywords`, `bx_persons_meta_locations`, `bx_persons_meta_mentions`, `bx_persons_scores`, `bx_persons_scores_track`, `bx_persons_skills`;
 
 -- PROFILES
 DELETE FROM sys_profiles WHERE `type` = 'bx_persons';
@@ -17,7 +17,7 @@ DELETE FROM `sys_transcoder_images_files` WHERE `transcoder_object` IN('bx_perso
 DELETE FROM `sys_objects_form` WHERE `module` = 'bx_persons';
 DELETE FROM `sys_form_displays` WHERE `module` = 'bx_persons';
 DELETE FROM `sys_form_inputs` WHERE `module` = 'bx_persons';
-DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN('bx_person_add', 'bx_person_delete', 'bx_person_edit', 'bx_person_edit_cover', 'bx_person_view', 'bx_person_view_full');
+DELETE FROM `sys_form_display_inputs` WHERE `display_name` IN('bx_person_add', 'bx_person_delete', 'bx_person_edit', 'bx_person_edit_cover', 'bx_person_view', 'bx_person_view_full', 'bx_person_skills', 'bx_person_skills_view');
 
 -- COMMENTS
 DELETE FROM `sys_objects_cmts` WHERE `Name` LIKE 'bx_persons%';

+ 4 - 0
modules/boonex/protean/data/template/studio/scripts/BxTemplStudioFormsField.php

@@ -41,6 +41,10 @@ class BxTemplStudioFormsFieldNumber extends BxBaseStudioFormsFieldNumber
 {
 }
 
+class BxTemplStudioFormsFieldNestedForm extends BxBaseStudioFormsFieldNestedForm
+{
+}
+
 class BxTemplStudioFormsFieldTime extends BxBaseStudioFormsFieldTime
 {
 }