Procházet zdrojové kódy

Merge branch 'master' of https://github.com/unaio/una

AntonLV před 6 roky
rodič
revize
0a86bb8913
27 změnil soubory, kde provedl 634 přidání a 109 odebrání
  1. 12 0
      inc/classes/BxDolConnection.php
  2. 11 0
      inc/classes/BxDolConnectionQuery.php
  3. 1 1
      modules/base/general/classes/BxBaseModGeneralDb.php
  4. 2 5
      modules/base/profile/classes/BxBaseModProfileModule.php
  5. 9 0
      modules/boonex/classes/classes/BxClssAlertsResponse.php
  6. 2 0
      modules/boonex/classes/classes/BxClssConfig.php
  7. 92 0
      modules/boonex/classes/classes/BxClssDb.php
  8. 34 0
      modules/boonex/classes/classes/BxClssFormEntry.php
  9. 184 0
      modules/boonex/classes/classes/BxClssModule.php
  10. 12 0
      modules/boonex/classes/classes/BxClssPageEntry.php
  11. 7 0
      modules/boonex/classes/install/langs/en.xml
  12. 6 0
      modules/boonex/classes/install/sql/enable.sql
  13. 73 32
      modules/boonex/classes/install/sql/install.sql
  14. 2 2
      modules/boonex/classes/install/sql/uninstall.sql
  15. 102 0
      modules/boonex/classes/js/main.js
  16. 31 0
      modules/boonex/classes/template/classes_add_module_form.html
  17. 3 0
      modules/boonex/classes/template/classes_class_row.html
  18. 14 0
      modules/boonex/classes/template/classes_in_context.html
  19. 22 0
      modules/boonex/classes/template/css/main.css
  20. 3 1
      modules/boonex/posts/install/sql/enable.sql
  21. 0 1
      modules/boonex/tasks/classes/BxTasksConfig.php
  22. 0 20
      modules/boonex/tasks/classes/BxTasksGridAdministration.php
  23. 1 6
      modules/boonex/tasks/install/sql/disable.sql
  24. 0 34
      modules/boonex/tasks/install/sql/enable.sql
  25. 0 4
      modules/boonex/tasks/install/sql/install.sql
  26. 0 2
      modules/boonex/tasks/install/sql/uninstall.sql
  27. 11 1
      template/scripts/BxBaseFormView.php

+ 12 - 0
inc/classes/BxDolConnection.php

@@ -391,6 +391,18 @@ class BxDolConnection extends BxDolFactory implements iBxDolFactoryObject
     {
         return $this->_oQuery->getConnectedContent($iInitiator, $isMutual, $iStart, $iLimit, $iOrder);
     }
+    
+    /**
+     * Get connected content IDs for specified type
+     * @param $iInitiator initiator of the connection
+     * @param $sType type of content
+     * @param $isMutual get mutual connections only
+     * @return array of available connections
+     */
+    public function getConnectedContentByType ($iInitiator, $sType, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        return $this->_oQuery->getConnectedContentByType($iInitiator, $sType, $isMutual, $iStart, $iLimit, $iOrder);
+    }
 
     /**
      * Get connected initiators IDs

+ 11 - 0
inc/classes/BxDolConnectionQuery.php

@@ -155,6 +155,17 @@ class BxDolConnectionQuery extends BxDolDb
         	'initiator' => $iInitiator
         ));
     }
+    
+    public function getConnectedContentByType ($iInitiator, $sType, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
+    {
+        $sWhere = " AND `c`.`initiator` = :initiator";
+        $sQuery = $this->_getConnectionsQuery($sWhere, 'INNER JOIN `sys_profiles` `p` ON `p`.`id` = `c`.`content` AND `p`.`type` = :type', '`c`.`content`', $isMutual, $iStart, $iLimit, $iOrder);
+       
+        return $this->getColumn($sQuery, array(
+        	'initiator' => $iInitiator,
+            'type' => $sType
+        ));
+    }
 
     public function getConnectedInitiators ($iContent, $isMutual = false, $iStart = 0, $iLimit = BX_CONNECTIONS_LIST_LIMIT, $iOrder = BX_CONNECTIONS_ORDER_NONE)
     {

+ 1 - 1
modules/base/general/classes/BxBaseModGeneralDb.php

@@ -82,7 +82,7 @@ class BxBaseModGeneralDb extends BxDolModuleDb
         $aMethod['params'][0] = "SELECT " . $sSelectClause . " FROM `" . $CNF['TABLE_ENTRIES'] . "` " . $sJoinClause . " WHERE 1 " . $sWhereClause . " " . $sOrderClause . " " . $sLimitClause;
 		return call_user_func_array(array($this, $aMethod['name']), $aMethod['params']);
     }
-    
+
     public function getEntriesNumByContext ($iProfileId)
     {
         $sQuery = $this->prepare ("SELECT COUNT(*) FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES'] . "` WHERE `" . $this->_oConfig->CNF['FIELD_ALLOW_VIEW_TO'] . "` = ?", - $iProfileId);

+ 2 - 5
modules/base/profile/classes/BxBaseModProfileModule.php

@@ -488,18 +488,15 @@ class BxBaseModProfileModule extends BxBaseModGeneralModule implements iBxDolCon
                 continue;
 
             if (BX_CONNECTIONS_TYPE_MUTUAL == $o->getType())
-                $a = array_merge($a, $o->getConnectedContent($iProfileId, true));
+                $a = array_merge($a, $o->getConnectedContentByType($iProfileId, $this->getName(), true));
             else
-                $a = array_merge($a, $o->getConnectedContent($iProfileId));
+                $a = array_merge($a, $o->getConnectedContentByType($iProfileId, $this->getName()));
         }
-
         $a = array_unique($a);
         $aRet = array();
         foreach ($a as $iConnectedProfileId) {
             if (!($oConnectedProfile = BxDolProfile::getInstance($iConnectedProfileId)))
                 continue;
-            if ($oConnectedProfile->getModule() != $this->getName())
-                continue;
 
             if (CHECK_ACTION_RESULT_ALLOWED === bx_srv($oConnectedProfile->getModule(), 'check_allowed_post_in_profile', array($oConnectedProfile->getContentId(), $iProfileId)))
                 $aRet[] = $iConnectedProfileId;

+ 9 - 0
modules/boonex/classes/classes/BxClssAlertsResponse.php

@@ -16,6 +16,15 @@ class BxClssAlertsResponse extends BxBaseModTextAlertsResponse
         $this->MODULE = 'bx_classes';
         parent::__construct();
     }
+
+    public function response($oAlert)
+    {
+        $CNF = $this->_oModule->_oConfig->CNF;
+
+        if ('bx_classes' == $oAlert->sUnit && 'commentPost' == $oAlert->sAction) {
+            $this->_oModule->_oDb->updateClassStatus($oAlert->iObject, $oAlert->iSender, 'replied');
+        }
+    }
 }
 
 /** @} */

+ 2 - 0
modules/boonex/classes/classes/BxClssConfig.php

@@ -29,6 +29,7 @@ class BxClssConfig extends BxBaseModTextConfig
 
             // database tables
             'TABLE_ENTRIES' => $aModule['db_prefix'] . 'classes',
+            'TABLE_MODULES' => $aModule['db_prefix'] . 'modules',
             'TABLE_ENTRIES_FULLTEXT' => 'title_text',
 
             // database fields
@@ -62,6 +63,7 @@ class BxClssConfig extends BxBaseModTextConfig
             'FIELD_ANONYMOUS' => 'anonymous',
             'FIELD_CMTS_SETTINGS' => 'cmts',
             'FIELD_AVAIL_SETTINGS' => 'avail',
+            'FIELD_MODULE' => 'module_id',
             'FIELDS_WITH_KEYWORDS' => 'auto', // can be 'auto', array of fields or comma separated string of field names, works only when OBJECT_METATAGS is specified
             'FIELDS_DELAYED_PROCESSING' => 'videos', // can be array of fields or comma separated string of field names
 

+ 92 - 0
modules/boonex/classes/classes/BxClssDb.php

@@ -14,10 +14,102 @@
  */
 class BxClssDb extends BxBaseModTextDb
 {
+    protected $_aStatuses = array(
+        1 => 'viewed',
+        2 => 'replied',
+    );
+
     function __construct(&$oConfig)
     {
         parent::__construct($oConfig);
     }
+
+    public function getEntriesByModule ($iModuleId)
+    {
+        $sQuery = $this->prepare ("SELECT * FROM `" . $this->_oConfig->CNF['TABLE_ENTRIES'] . "` WHERE `module_id` = ? ORDER BY `order`", $iModuleId);
+        return $this->getAll($sQuery);
+    }
+
+    public function getEntriesModulesByContext ($iProfileId, $bAsPairs = false)
+    {
+        $sQuery = $this->prepare ("SELECT * FROM `" . $this->_oConfig->CNF['TABLE_MODULES'] . "` WHERE `profile_id` = ? ORDER BY `order`", $iProfileId);
+        if ($bAsPairs)
+            return $this->getPairs($sQuery, 'id', 'module_title');
+        else
+            return $this->getAll($sQuery);
+    }
+
+    public function updateModulesOrder ($iProfileId, $aModulesOrder)
+    {
+        $iAffected = 0;
+        foreach ($aModulesOrder as $iOrder => $iModuleId) {
+            $iAffected += ($this->query("UPDATE `" . $this->_oConfig->CNF['TABLE_MODULES'] . "` SET `order` = :order WHERE `profile_id` = :profile_id AND `id` = :module_id", array(
+                'order' => $iOrder,
+                'profile_id' => $iProfileId,
+                'module_id' => $iModuleId,
+            )) ? 1 : 0);
+        }        
+        return $iAffected;
+    }
+
+    public function updateClassesOrder($iProfileId, $iModuleId, $aClassesOrder)
+    {
+        $iAffected = 0;
+        foreach ($aClassesOrder as $iOrder => $iClassId) {
+            $iAffected += ($this->query("UPDATE `" . $this->_oConfig->CNF['TABLE_ENTRIES'] . "` SET `order` = :order, `module_id` = :module_id WHERE `allow_view_to` = :profile_id AND `id` = :class_id", array(
+                'order' => $iOrder,
+                'profile_id' => -$iProfileId,
+                'module_id' => $iModuleId,
+                'class_id' => $iClassId,
+            )) ? 1 : 0);
+        }        
+        return $iAffected;
+    }
+
+    public function isClassCompleted($iClassId, $iStudentProfileId)
+    {
+        if (!($aContentInfo = $this->getContentInfoById($iClassId)))
+            return false;
+
+        return $this->getClassStatus($iClassId, $iStudentProfileId, (int)$aContentInfo['completed_when']);
+    }
+
+    public function getClassStatus($iClassId, $iStudentProfileId, $mixedStatus)
+    {
+        if (is_numeric($mixedStatus) && is_int($mixedStatus) && isset($this->_aStatuses[$mixedStatus]))
+            $mixedStatus = $this->_aStatuses[$mixedStatus];
+        elseif (!in_array($mixedStatus, $this->_aStatuses, true))
+            return false;
+
+        return $this->getOne("SELECT `$mixedStatus` FROM `bx_classes_statuses` WHERE `class_id` = :class AND `student_profile_id` = :student", array(
+            'class' => $iClassId,
+            'student' => $iStudentProfileId,
+        ));
+    }
+
+    public function updateClassStatus($iClassId, $iStudentProfileId, $sStatus)
+    {
+        if (!in_array($sStatus, $this->_aStatuses))
+            return false;
+
+        if ($this->getOne("SELECT `id` FROM `bx_classes_statuses` WHERE `class_id` = :class AND `student_profile_id` = :student", array(
+            'class' => $iClassId,
+            'student' => $iStudentProfileId,
+        ))) {
+            return $this->query("UPDATE `bx_classes_statuses` SET `$sStatus` = :ts WHERE `class_id` = :class AND `student_profile_id` = :student", array(
+                'ts' => time(),
+                'class' => $iClassId,
+                'student' => $iStudentProfileId,
+            ));
+        }
+        else {
+            return $this->query("INSERT INTO `bx_classes_statuses` SET `class_id` = :class, `student_profile_id` = :student, `$sStatus` = :ts", array(
+                'ts' => time(),
+                'class' => $iClassId,
+                'student' => $iStudentProfileId,
+            ));
+        }
+    }
 }
 
 /** @} */

+ 34 - 0
modules/boonex/classes/classes/BxClssFormEntry.php

@@ -15,6 +15,7 @@
 class BxClssFormEntry extends BxBaseModTextFormEntry
 {
     protected $_sGhostTemplateCover = 'form_ghost_template_cover.html';
+    protected $_oProfileContext = null;
 	
     public function __construct($aInfo, $oTemplate = false)
     {
@@ -98,6 +99,29 @@ class BxClssFormEntry extends BxBaseModTextFormEntry
         }
 
         parent::initChecker ($aValues, $aSpecificValues);
+
+        if (isset($this->aInputs[$CNF['FIELD_ALLOW_VIEW_TO']])) {
+
+            // try to get context from form POST
+            $iProfileId = (int)bx_get($CNF['FIELD_ALLOW_VIEW_TO']);
+
+            // try to get context from the form saved value (in case of "edit" form)
+            if ($iProfileId >= 0 && $this->aInputs[$CNF['FIELD_ALLOW_VIEW_TO']]['value'] < 0)
+                $iProfileId = $this->aInputs[$CNF['FIELD_ALLOW_VIEW_TO']]['value'];
+
+            // try to get context from GET param (in case of "create" form)
+            if ($iProfileId >= 0)
+                $iProfileId = bx_get('profile_id');
+
+            $iProfileId = abs($iProfileId);
+
+            if ($iProfileId)
+                $this->_oProfileContext = BxDolProfile::getInstance($iProfileId);
+
+            if (isset($this->aInputs[$CNF['FIELD_MODULE']]) && $this->_oProfileContext) {
+                $this->aInputs[$CNF['FIELD_MODULE']]['values'] = $this->_oModule->_oDb->getEntriesModulesByContext($this->_oProfileContext->id(), true);
+            }
+        }
     }
 
     public function insert ($aValsToAdd = array(), $isIgnore = false)
@@ -175,6 +199,16 @@ class BxClssFormEntry extends BxBaseModTextFormEntry
             'editor_id' => isset($CNF['FIELD_TEXT_ID']) ? $CNF['FIELD_TEXT_ID'] : ''
     	);
     }
+
+    function getCode($bDynamicMode = false)
+    {
+        if (!$this->_bViewMode && !$this->_oProfileContext)
+            return MsgBox(_t('_bx_classes_txt_err_cant_add_class_without_context'));
+
+        // TODO: check permission for adding to context
+
+        return parent::getCode($bDynamicMode);
+    }
 }
 
 /** @} */

+ 184 - 0
modules/boonex/classes/classes/BxClssModule.php

@@ -28,6 +28,128 @@ class BxClssModule extends BxBaseModTextModule
         ));
     }
 
+    public function actionReorderClasses($iProfileId = 0)
+    {
+        $oProfileContext = $iProfileId ? BxDolProfile::getInstance($iProfileId) : null;
+        if (!$oProfileContext) {
+            echo _t('_sys_txt_error_occured');
+            exit;
+        }
+
+        // TODO: check permission for reordering
+
+        foreach ($_REQUEST as $k => $v) {
+            if (0 !== strncmp($k, 'classes_order_', 14))
+                continue;
+            $iModuleId = (int)str_replace('classes_order_', '', $k);
+            if (!$iModuleId)
+                continue;
+            
+            $aClassesOrder = explode(',', $v);
+            if (!$aClassesOrder || !is_array($aClassesOrder))
+                continue;
+
+            $this->_oDb->updateClassesOrder($iProfileId, $iModuleId, $aClassesOrder);
+        }
+    }
+
+    public function actionReorderModules($iProfileId = 0)
+    {
+        $oProfileContext = $iProfileId ? BxDolProfile::getInstance($iProfileId) : null;
+        if (!$oProfileContext) {
+            echo _t('_sys_txt_error_occured');
+            exit;
+        }
+
+        // TODO: check permission for reordering
+
+        $aModulesOrder = bx_get('modules_order');
+        if (!$aModulesOrder || !is_array($aModulesOrder)) {
+            echo _t('_sys_txt_error_occured');
+            exit;
+        }
+
+        $this->_oDb->updateModulesOrder($iProfileId, $aModulesOrder);
+    }
+
+    public function actionAddModule($iProfileId = 0)
+    {
+        $oProfileContext = $iProfileId ? BxDolProfile::getInstance($iProfileId) : null;
+        if (!$oProfileContext) {
+            echoJson(array('action' => 'ShowMsg', 'msg' => _t('_sys_txt_error_occured')));
+            exit;
+        }
+
+        // TODO: check permission for adding to context
+
+        $aForm = array(
+            'form_attrs' => array(
+                'id' => 'bx-classes-module-add',
+                'action' => BX_DOL_URL_ROOT . 'modules/index.php?r=classes/add_module/' . $iProfileId,
+                'method' => 'post',
+            ),
+            'params' => array (
+                'db' => array(
+                    'submit_name' => 'do_submit',
+                    'table' => $this->_oConfig->CNF['TABLE_MODULES'],
+                    'key' => 'id',
+                ),
+            ),
+            'inputs' => array(
+                'module_title' => array(
+                    'type' => 'text',
+                    'name' => 'module_title',
+                    'caption' => 'Module title', // TODO: translate
+                    'checker' => array(
+                        'func' => 'Avail',
+                        'error' => 'Something must be entered', // TODO: translate
+                    ),
+                    'db' => array('pass' => 'Xss'),
+                ),
+                'submit' => array(
+                    'type' => 'input_set',
+                    0 => array (
+                        'type' => 'submit',
+                        'name' => 'do_submit',
+                        'value' => _t('_Submit'),
+                    ),
+                    1 => array (
+                        'type' => 'reset',
+                        'name' => 'close',
+                        'value' => _t('_Cancel'),
+                        'attrs' => array(
+                            'class' => 'bx-def-margin-sec-left',
+                            'onclick' => "$('.bx-popup-applied:visible').dolPopupHide();",
+                        ),
+                    ),
+                ),
+            ),
+        );
+        $oForm = new BxTemplFormView($aForm);
+        $oForm->initChecker();
+        if ($oForm->isSubmittedAndValid()) {
+            $iModuleId = $oForm->insert(array(
+                'profile_id' => $iProfileId,
+                'author' => bx_get_logged_profile_id(),
+                'added' => time(),
+                'changed' => time(),
+                'order' => 123, // TODO: calc max order
+            ));
+            if ($iModuleId) {
+                echoJson(array('action' => 'ReloadLessonsAndClosePopup'));
+            }
+            else {
+                echoJson(array('action' => 'ShowMsg', 'msg' => _t('_sys_txt_error_occured')));
+            }
+        } 
+        else {
+            echo $this->_oTemplate->parseHtmlByName('classes_add_module_form.html', array(
+                'form' => $oForm->getCode(),
+                'profile_id' => $iProfileId,
+            ));
+        }
+    }
+
     /**
      * Entry post for Timeline module
      */
@@ -65,6 +187,68 @@ class BxClssModule extends BxBaseModTextModule
 
         return parent::serviceCheckAllowedCommentsView($iContentId, $sObjectComments);
     }
+
+    public function serviceClassesInContext ($iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = (int)bx_get('id') ? bx_get('id') : bx_get('profile_id');
+
+        $aInputs = array();
+        $aModules = $this->_oDb->getEntriesModulesByContext($iProfileId);
+        foreach ($aModules as $aModule) {
+            $aInputs['module' . $aModule['id']] = array(
+                'type' => 'block_header',
+                'caption' => $aModule['module_title'],
+                'collapsed' => false,
+                'attrs' => array('id' => 'module_' . $aModule['id'], 'class' => ''),
+            );
+            $aClasses = $this->_oDb->getEntriesByModule($aModule['id']);
+            $sContent = '';
+            if ($aClasses) {
+                foreach ($aClasses as $aClass) {
+                    $sContent .= $this->_oTemplate->parseHtmlByName('classes_class_row.html', array(
+                        'id' => $aClass['id'],
+                        'title' => $aClass['title'] . '(' . ($this->serviceIsClassCompleted($aClass['id']) ? 'completed' : 'not completed') . ')',
+                        'url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=' . $this->_oConfig->CNF['URI_VIEW_ENTRY'] . '&id=' . $aClass['id']),
+                    ));
+                }
+            }
+
+            $aInputs['class_module' . $aModule['id']] = array(
+                'type' => 'custom',
+                'name' => 'class_module' . $aModule['id'],
+                'caption' => '',
+                'content' => $sContent,
+            );
+
+        }
+
+        $aForm = array(
+            'form_attrs' => array(
+                'id' => 'bx-classes-list-view',
+            ),
+            'inputs' => $aInputs,
+        );
+        $oForm = new BxTemplFormView($aForm);
+        $oForm->setShowEmptySections(true);
+
+        $this->_oTemplate->addCss('main.css');
+        $this->_oTemplate->addJs('main.js');
+
+        return $this->_oTemplate->parseHtmlByName('classes_in_context.html', array(
+            'profile_id' => $iProfileId,
+            'new_class_url' => BX_DOL_URL_ROOT . BxDolPermalinks::getInstance()->permalink('page.php?i=create-class&profile_id=' . $iProfileId),
+            'form' => $oForm->getCode(),
+        ));
+    }
+
+    public function serviceIsClassCompleted ($iClassId, $iProfileId = 0)
+    {
+        if (!$iProfileId)
+            $iProfileId = bx_get_logged_profile_id();
+
+        return $this->_oDb->isClassCompleted($iClassId, $iProfileId);
+    }
 }
 
 /** @} */

+ 12 - 0
modules/boonex/classes/classes/BxClssPageEntry.php

@@ -27,6 +27,18 @@ class BxClssPageEntry extends BxBaseModTextPageEntry
     		'icon' => ''
     	)));
     }
+
+    public function getCode ()
+    {
+        $s = parent::getCode ();
+
+        // mark class as viewed
+        $CNF = &$this->_oModule->_oConfig->CNF;
+        if ($this->_aContentInfo && isLogged())
+            $this->_oModule->_oDb->updateClassStatus($this->_aContentInfo[$CNF['FIELD_ID']], bx_get_logged_profile_id(), 'viewed');
+
+        return $s;
+    }
 }
 
 /** @} */

+ 7 - 0
modules/boonex/classes/install/langs/en.xml

@@ -61,6 +61,8 @@
     <string name="_bx_classes_form_entry_input_sys_attachments"><![CDATA[Attachments]]></string>
     <string name="_bx_classes_form_entry_input_cmts"><![CDATA[Comments settings]]></string>
     <string name="_bx_classes_form_entry_input_avail"><![CDATA[Availability]]></string>
+    <string name="_bx_classes_form_entry_input_module"><![CDATA[Module]]></string>
+    <string name="_bx_classes_form_entry_input_completed_when"><![CDATA[Class is completed when]]></string>
 
     <string name="_bx_classes_form_poll"><![CDATA[Polls]]></string>
     <string name="_bx_classes_form_poll_display_add"><![CDATA[Add Poll]]></string>
@@ -211,6 +213,10 @@
     <string name="_bx_classes_cmts_all_shown"><![CDATA[All comments are shown]]></string>
     <string name="_bx_classes_cmts_own_and_admins"><![CDATA[Own and admin comments are shown]]></string>
 
+    <string name="_bx_classes_pre_lists_completed_when"><![CDATA[Class is completed when]]></string>
+    <string name="_bx_classes_completed_when_viewed"><![CDATA[Viewed]]></string>
+    <string name="_bx_classes_completed_when_replied"><![CDATA[Replied]]></string>
+
     <string name="_bx_classes_txt_all_entries_in"><![CDATA[<a href="{0}">All Classes in {1} ({2})</a>]]></string>
     <string name="_bx_classes_txt_all_entries_by"><![CDATA[{0} classes]]></string>
     <string name="_bx_classes_txt_sample_single"><![CDATA[class]]></string>
@@ -225,6 +231,7 @@
     <string name="_bx_classes_txt_scheduled_awaiting"><![CDATA[Class publishing date is {date_publish_uf}]]></string>
 
     <string name="_bx_classes_txt_err_cannot_perform_action"><![CDATA[Cannot perform action. Please report.]]></string>
+    <string name="_bx_classes_txt_err_cant_add_class_without_context"><![CDATA[Class can be added into context only]]></string>
 
     <string name="_bx_classes_txt_poll_view_answers"><![CDATA[poll]]></string>
     <string name="_bx_classes_txt_poll_view_results"><![CDATA[results]]></string>

+ 6 - 0
modules/boonex/classes/install/sql/enable.sql

@@ -98,6 +98,10 @@ INSERT INTO `sys_objects_page`(`object`, `title_system`, `title`, `module`, `lay
 INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES 
 ('bx_classes_administration', 1, 'bx_classes', '_bx_classes_page_block_title_system_manage_administration', '_bx_classes_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:10:\"bx_classes\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
 
+-- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
+SET @iPBCellGroup = 4;
+INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_classes', '_bx_classes_page_block_title_group_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:10:"bx_classes";s:6:"method";s:18:"classes_in_context";s:6:"params";a:1:{i:0;s:12:"{profile_id}";}}', 0, 0, 0);
 
 -- MENU: add to "add content" menu
 
@@ -361,6 +365,8 @@ INSERT INTO `sys_alerts` (`unit`, `action`, `handler_id`) VALUES
 ('system', 'save_setting', @iHandler),
 ('profile', 'delete', @iHandler),
 
+('bx_classes', 'commentPost', @iHandler),
+
 ('bx_classes_videos_mp4', 'transcoded', @iHandler);
 
 

+ 73 - 32
modules/boonex/classes/install/sql/install.sql

@@ -3,14 +3,17 @@ CREATE TABLE IF NOT EXISTS `bx_classes_classes` (
   `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
   `author` int(11) NOT NULL,
   `added` int(11) NOT NULL,
-  `changed` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,  
   `published` int(11) NOT NULL,
+  `module_id` int(10) unsigned NOT NULL,
+  `order` int(11) NOT NULL,
   `start_date` int(11) NOT NULL,
   `end_date` int(11) NOT NULL,
   `thumb` int(11) NOT NULL,
   `title` varchar(255) NOT NULL,
   `avail` int(11) NOT NULL,
   `cmts` int(11) NOT NULL,
+  `completed_when` int(11) NOT NULL,
   `text` mediumtext NOT NULL,
   `labels` text NOT NULL,
   `location` text NOT NULL,
@@ -33,6 +36,29 @@ CREATE TABLE IF NOT EXISTS `bx_classes_classes` (
   FULLTEXT KEY `title_text` (`title`,`text`)
 );
 
+-- TABLE: modules
+CREATE TABLE IF NOT EXISTS `bx_classes_modules` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `profile_id` int(10) unsigned NOT NULL,
+  `module_title` varchar(255) NOT NULL,
+  `author` int(11) NOT NULL,
+  `added` int(11) NOT NULL,
+  `changed` int(11) NOT NULL,
+  `order` int(11) NOT NULL,
+  PRIMARY KEY (`id`)
+);
+
+-- TABLE: status
+CREATE TABLE IF NOT EXISTS `bx_classes_statuses` (
+  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
+  `class_id` int(10) unsigned NOT NULL,
+  `student_profile_id` int(11) NOT NULL,
+  `viewed` int(11) NOT NULL,
+  `replied` int(11) NOT NULL,
+  PRIMARY KEY (`id`),
+  UNIQUE `class_student` (`class_id`,`student_profile_id`)
+);
+
 -- TABLE: storages & transcoders
 CREATE TABLE IF NOT EXISTS `bx_classes_covers` (
   `id` int(11) NOT NULL AUTO_INCREMENT,
@@ -404,6 +430,8 @@ INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `ch
 ('bx_classes', 'bx_classes', 'title', '', '', 0, 'text', '_bx_classes_form_entry_input_sys_title', '_bx_classes_form_entry_input_title', '', 1, 0, 0, '', '', '', 'Avail', '', '_bx_classes_form_entry_input_title_err', 'Xss', '', 1, 0),
 ('bx_classes', 'bx_classes', 'avail', '', '#!bx_classes_avail', 0, 'select', '', '_bx_classes_form_entry_input_avail', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_classes', 'bx_classes', 'cmts', '', '#!bx_classes_cmts', 0, 'select', '', '_bx_classes_form_entry_input_cmts', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_classes', 'bx_classes', 'completed_when', '', '#!bx_classes_completed_when', 0, 'select', '', '_bx_classes_form_entry_input_completed_when', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
+('bx_classes', 'bx_classes', 'module_id', '', '', 0, 'select', '', '_bx_classes_form_entry_input_module', '', 1, 0, 0, '', '', '', '', '', '', 'Int', '', 1, 0),
 ('bx_classes', 'bx_classes', 'added', '', '', 0, 'datetime', '_bx_classes_form_entry_input_sys_date_added', '_bx_classes_form_entry_input_date_added', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_classes', 'bx_classes', 'changed', '', '', 0, 'datetime', '_bx_classes_form_entry_input_sys_date_changed', '_bx_classes_form_entry_input_date_changed', '', 0, 0, 0, '', '', '', '', '', '', '', '', 1, 0),
 ('bx_classes', 'bx_classes', 'start_date', '', '', 0, 'datetime', '', '_bx_classes_form_entry_input_date_start_date', '', 0, 0, 0, '', '', '', '', '', '', 'DateTimeTs', '', 1, 0),
@@ -416,42 +444,47 @@ INSERT INTO `sys_form_inputs`(`object`, `module`, `name`, `value`, `values`, `ch
 
 INSERT INTO `sys_form_display_inputs`(`display_name`, `input_name`, `visible_for_levels`, `active`, `order`) VALUES 
 ('bx_classes_entry_add', 'covers', 2147483647, 1, 1),
-('bx_classes_entry_add', 'title', 2147483647, 1, 2),
-('bx_classes_entry_add', 'text', 2147483647, 1, 3),
-('bx_classes_entry_add', 'attachments', 2147483647, 1, 4),
-('bx_classes_entry_add', 'pictures', 2147483647, 1, 5),
-('bx_classes_entry_add', 'videos', 2147483647, 1, 6),
-('bx_classes_entry_add', 'files', 2147483647, 1, 7),
-('bx_classes_entry_add', 'polls', 2147483647, 1, 8),
-('bx_classes_entry_add', 'start_date', 2147483647, 1, 9),
-('bx_classes_entry_add', 'end_date', 2147483647, 1, 10),
-('bx_classes_entry_add', 'avail', 2147483647, 1, 11),
-('bx_classes_entry_add', 'cmts', 2147483647, 1, 12),
-('bx_classes_entry_add', 'allow_view_to', 2147483647, 1, 13),
-('bx_classes_entry_add', 'do_publish', 2147483647, 1, 14),
+('bx_classes_entry_add', 'module_id', 2147483647, 1, 2),
+('bx_classes_entry_add', 'title', 2147483647, 1, 3),
+('bx_classes_entry_add', 'text', 2147483647, 1, 4),
+('bx_classes_entry_add', 'attachments', 2147483647, 1, 5),
+('bx_classes_entry_add', 'pictures', 2147483647, 1, 6),
+('bx_classes_entry_add', 'videos', 2147483647, 1, 7),
+('bx_classes_entry_add', 'files', 2147483647, 1, 8),
+('bx_classes_entry_add', 'polls', 2147483647, 1, 9),
+('bx_classes_entry_add', 'start_date', 2147483647, 1, 10),
+('bx_classes_entry_add', 'end_date', 2147483647, 1, 11),
+('bx_classes_entry_add', 'completed_when', 2147483647, 1, 12),
+('bx_classes_entry_add', 'avail', 2147483647, 1, 13),
+('bx_classes_entry_add', 'cmts', 2147483647, 1, 14),
+('bx_classes_entry_add', 'allow_view_to', 2147483647, 1, 15),
+('bx_classes_entry_add', 'do_publish', 2147483647, 1, 16),
 
 ('bx_classes_entry_delete', 'delete_confirm', 2147483647, 1, 1),
 ('bx_classes_entry_delete', 'do_submit', 2147483647, 1, 2),
 
 ('bx_classes_entry_edit', 'covers', 2147483647, 1, 1),
-('bx_classes_entry_edit', 'title', 2147483647, 1, 2),
-('bx_classes_entry_edit', 'text', 2147483647, 1, 3),
-('bx_classes_entry_edit', 'attachments', 2147483647, 1, 4),
-('bx_classes_entry_edit', 'pictures', 2147483647, 1, 5),
-('bx_classes_entry_edit', 'videos', 2147483647, 1, 6),
-('bx_classes_entry_edit', 'files', 2147483647, 1, 7),
-('bx_classes_entry_edit', 'polls', 2147483647, 1, 8),
-('bx_classes_entry_edit', 'start_date', 2147483647, 1, 9),
-('bx_classes_entry_edit', 'end_date', 2147483647, 1, 10),
-('bx_classes_entry_edit', 'avail', 2147483647, 1, 11),
-('bx_classes_entry_edit', 'cmts', 2147483647, 1, 12),
-('bx_classes_entry_edit', 'allow_view_to', 2147483647, 1, 13),
-('bx_classes_entry_edit', 'do_submit', 2147483647, 1, 14),
-
-('bx_classes_entry_view', 'added', 2147483647, 1, 1),
-('bx_classes_entry_view', 'changed', 2147483647, 1, 2),
-('bx_classes_entry_view', 'start_date', 2147483647, 1, 3),
-('bx_classes_entry_view', 'end_date', 2147483647, 1, 4);
+('bx_classes_entry_edit', 'module_id', 2147483647, 1, 2),
+('bx_classes_entry_edit', 'title', 2147483647, 1, 3),
+('bx_classes_entry_edit', 'text', 2147483647, 1, 4),
+('bx_classes_entry_edit', 'attachments', 2147483647, 1, 5),
+('bx_classes_entry_edit', 'pictures', 2147483647, 1, 6),
+('bx_classes_entry_edit', 'videos', 2147483647, 1, 7),
+('bx_classes_entry_edit', 'files', 2147483647, 1, 8),
+('bx_classes_entry_edit', 'polls', 2147483647, 1, 9),
+('bx_classes_entry_edit', 'start_date', 2147483647, 1, 10),
+('bx_classes_entry_edit', 'end_date', 2147483647, 1, 11),
+('bx_classes_entry_edit', 'completed_when', 2147483647, 1, 12),
+('bx_classes_entry_edit', 'avail', 2147483647, 1, 13),
+('bx_classes_entry_edit', 'cmts', 2147483647, 1, 14),
+('bx_classes_entry_edit', 'allow_view_to', 2147483647, 1, 15),
+('bx_classes_entry_edit', 'do_submit', 2147483647, 1, 16),
+
+('bx_classes_entry_view', 'module_id', 2147483647, 1, 1),
+('bx_classes_entry_view', 'added', 2147483647, 1, 2),
+('bx_classes_entry_view', 'changed', 2147483647, 1, 3),
+('bx_classes_entry_view', 'start_date', 2147483647, 1, 4),
+('bx_classes_entry_view', 'end_date', 2147483647, 1, 5);
 
 -- FORMS: poll
 INSERT INTO `sys_objects_form` (`object`, `module`, `title`, `action`, `form_attrs`, `submit_name`, `table`, `key`, `uri`, `uri_title`, `params`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES
@@ -493,6 +526,14 @@ INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALU
 ('bx_classes_cmts', '2', 2, '_bx_classes_cmts_all_shown', ''),
 ('bx_classes_cmts', '3', 3, '_bx_classes_cmts_own_and_admins', '');
 
+
+INSERT INTO `sys_form_pre_lists`(`key`, `title`, `module`, `use_for_sets`) VALUES
+('bx_classes_completed_when', '_bx_classes_pre_lists_completed_when', 'bx_classes', '0');
+
+INSERT INTO `sys_form_pre_values`(`Key`, `Value`, `Order`, `LKey`, `LKey2`) VALUES
+('bx_classes_completed_when', '1', 1, '_bx_classes_completed_when_viewed', ''),
+('bx_classes_completed_when', '2', 2, '_bx_classes_completed_when_replied', '');
+
 -- 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
 ('bx_classes', 'bx_classes', 'bx_classes_cmts', 1, 5000, 1000, 3, 5, 3, 'tail', 1, 'bottom', 1, 1, 1, -3, 1, 'cmt', 'page.php?i=view-class&id={object_id}', '', 'bx_classes_classes', 'id', 'author', 'title', 'comments', '', ''),

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

@@ -1,6 +1,6 @@
 
 -- TABLES
-DROP TABLE IF EXISTS `bx_classes_classes`, `bx_classes_covers`, `bx_classes_files`, `bx_classes_photos`, `bx_classes_photos_resized`, `bx_classes_videos`, `bx_classes_videos_resized`, `bx_classes_cmts`, `bx_classes_cmts_notes`, `bx_classes_votes`, `bx_classes_votes_track`, `bx_classes_reactions`, `bx_classes_reactions_track`, `bx_classes_views_track`, `bx_classes_meta_keywords`, `bx_classes_meta_locations`, `bx_classes_meta_mentions`, `bx_classes_reports`, `bx_classes_reports_track`, `bx_classes_favorites_track`, `bx_classes_scores`, `bx_classes_scores_track`, `bx_classes_polls`, `bx_classes_polls_answers`, `bx_classes_polls_answers_votes`, `bx_classes_polls_answers_votes_track`;
+DROP TABLE IF EXISTS `bx_classes_classes`, `bx_classes_modules`, `bx_classes_statuses`, `bx_classes_covers`, `bx_classes_files`, `bx_classes_photos`, `bx_classes_photos_resized`, `bx_classes_videos`, `bx_classes_videos_resized`, `bx_classes_cmts`, `bx_classes_cmts_notes`, `bx_classes_votes`, `bx_classes_votes_track`, `bx_classes_reactions`, `bx_classes_reactions_track`, `bx_classes_views_track`, `bx_classes_meta_keywords`, `bx_classes_meta_locations`, `bx_classes_meta_mentions`, `bx_classes_reports`, `bx_classes_reports_track`, `bx_classes_favorites_track`, `bx_classes_scores`, `bx_classes_scores_track`, `bx_classes_polls`, `bx_classes_polls_answers`, `bx_classes_polls_answers_votes`, `bx_classes_polls_answers_votes_track`;
 
 -- STORAGES & TRANSCODERS
 DELETE FROM `sys_objects_storage` WHERE `object` LIKE 'bx_classes_%';
@@ -19,7 +19,7 @@ DELETE FROM `sys_form_display_inputs` WHERE `display_name` LIKE 'bx_classes_%';
 -- PRE-VALUES
 DELETE FROM `sys_form_pre_lists` WHERE `module` = 'bx_classes';
 
-DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_classes_avail', 'bx_classes_cmts');
+DELETE FROM `sys_form_pre_values` WHERE `Key` IN('bx_classes_avail', 'bx_classes_cmts', 'bx_classes_completed_when');
 
 -- CATEGORIES
 DELETE FROM `sys_categories` WHERE `module` = 'bx_classes';

+ 102 - 0
modules/boonex/classes/js/main.js

@@ -0,0 +1,102 @@
+/**
+ * Copyright (c) UNA, Inc - https://una.io
+ * MIT License - https://opensource.org/licenses/MIT
+ *
+ * @defgroup    Classes Classes
+ * @ingroup     UnaModules
+ *
+ * @{
+ */
+
+function bx_classes_show_module_add_form(iProfileId)
+{
+    var sActionUrl = sUrlRoot + 'modules/index.php?r=classes/add_module/' + iProfileId;
+    $(window).dolPopupAjax({url: sActionUrl, closeOnOuterClick: false});
+}
+
+function bx_classes_reorder_classes(iProfileId, bEnable)
+{
+    var eCourse = jQuery('.bx-course-classes .bx-form-advanced-wrapper');
+    var eSortable = jQuery('.bx-course-classes .bx-form-input-wrapper-custom');
+    var sHandle = '<i class="handle sys-icon move bx-def-padding-right"></i>';
+    if (bEnable) {
+        jQuery('.bx-course-classes, .bx-course-controls').addClass('bx-course-reordering-mode');
+        if (!eCourse.find('.bx-classes-class-title .handle').size())
+            eSortable.find('.bx-classes-class-title').prepend(sHandle);
+        if (eSortable.hasClass('ui-sortable-disabled')) {
+            eSortable.sortable('enable');
+        }
+        else if (!eSortable.hasClass('ui-sortable')) {
+            eSortable.sortable({
+                items:'.bx-classes-class',
+                connectWith: ".bx-form-input-wrapper-custom",
+                handle: '.handle',
+                placeholder: 'bx-classes-placeholder sys-icon arrow-right',
+                forcePlaceholderSize: true, 
+                dropOnEmpty: true,
+                stop: function(oEvent, oUi) {
+                    var a = eCourse.find('.bx-form-section-wrapper > .bx-form-section'); 
+                    var s = '';
+                    var i = 0;
+                    $.each(a, function () {
+                        var aa = $(this).find('.bx-classes-class');
+                        var iModuleId = $(this).attr('id').replace('module_', '');
+                        s += '&classes_order_' +iModuleId + '=';
+                        $.each(aa, function () {
+                            s += $(this).attr('id').replace('class_', '') + ',';
+                        });
+                        s = s.replace(/,$/, '');
+                    });
+                    var sActionUrl = sUrlRoot + 'modules/index.php?r=classes/reorder_classes/' + iProfileId + s;
+                    $.post(sActionUrl);
+                }
+
+            });
+        }
+        glBxClassesSortableClassesInitialized = true;
+    }
+    else if (!bEnable && 'undefined' !== typeof(glBxClassesSortableClassesInitialized)) {
+        eSortable.sortable('disable');
+        eSortable.find('.bx-classes-class .handle').remove();
+        jQuery('.bx-course-classes, .bx-course-controls').removeClass('bx-course-reordering-mode');
+    }
+}
+
+function bx_classes_reorder_modules(iProfileId, bEnable)
+{
+    var eCourse = jQuery('.bx-course-classes .bx-form-advanced-wrapper');
+    var sHandle = '<i class="handle sys-icon move bx-def-padding-leftright"></i>';
+    if (bEnable) {
+        jQuery('.bx-course-classes, .bx-course-controls').addClass('bx-course-reordering-mode');
+        if (!eCourse.find('legend .handle').size())
+            eCourse.find('legend').prepend(sHandle);
+        if (eCourse.hasClass('ui-sortable-disabled')) {
+            eCourse.sortable('enable');
+        }
+        else if (!eCourse.hasClass('ui-sortable')) {
+            eCourse.sortable({
+                items:'.bx-form-section-wrapper',
+                handle: '.handle',
+                stop: function(oEvent, oUi) {
+                    var a = eCourse.find('.bx-form-section-wrapper > .bx-form-section'); 
+                    var s = '';
+                    var i = 0;
+                    $.each(a, function () {                        
+                        s += '&modules_order[]=' + $(this).attr('id').replace('module_', '');
+                    });
+                    var sActionUrl = sUrlRoot + 'modules/index.php?r=classes/reorder_modules/' + iProfileId + s;
+                    $.post(sActionUrl);
+                }
+
+            });
+        }
+        glBxClassesSortableModulesInitialized = true;
+    }
+    else if (!bEnable && 'undefined' !== typeof(glBxClassesSortableModulesInitialized)) {
+        eCourse.sortable('disable');
+        eCourse.find('legend .handle').remove();
+        jQuery('.bx-course-classes, .bx-course-controls').removeClass('bx-course-reordering-mode');
+    }
+}
+
+/** @} */

+ 31 - 0
modules/boonex/classes/template/classes_add_module_form.html

@@ -0,0 +1,31 @@
+<div id="bx-classes-add-module-form" class="bx-classes-add-page-form">
+    __form__
+</div>
+<script>
+    $(document).ready(function () {
+        $("#bx-classes-add-module-form form").ajaxForm({
+            url: sUrlRoot + 'modules/index.php?r=classes/add_module/__profile_id__',
+            beforeSubmit: function (formData, $form, options) {
+                bx_loading($("#bx-classes-add-module-form form"), true);
+            },
+            success: function (data) {
+                if ('{' == data[0]) {
+                    var oResponce = JSON.parse(data);
+                    if ('ReloadLessonsAndClosePopup' == oResponce.action) {
+                        $('.bx-popup-applied:visible').dolPopupHide();
+                        loadDynamicBlockAuto('.bx-course-controls');
+                    } 
+                    else if ('ShowMsg' == oResponce.action) {
+                        bx_alert(oResponce.msg);
+                    }
+                    else {
+                        bx_alert('<bx_text_js:_sys_txt_error_occured />');
+                    }
+                }
+                else {
+                    $("#bx-classes-add-module-form").parent().html(data).bxProcessHtml();
+                }
+            }
+        });
+    });
+</script>

+ 3 - 0
modules/boonex/classes/template/classes_class_row.html

@@ -0,0 +1,3 @@
+<div id="class___id__" class="bx-classes-class bx-def-margin-thd-topbottom">
+    <div class="bx-classes-class-title"><a href="__url__">__title__</a></div>
+</div>

+ 14 - 0
modules/boonex/classes/template/classes_in_context.html

@@ -0,0 +1,14 @@
+<div class="bx-course-controls bx-def-margin-bottom bx-clearfix">
+    <div class="bx-course-controls-1 bx-clearfix">
+        <a class="bx-btn bx-def-margin-right" href="__new_class_url__">Add Class</a>
+        <a class="bx-btn" href="javascript:void(0);" onclick="bx_classes_show_module_add_form('__profile_id__')">Add Module</a>
+    </div>
+    <div class="bx-course-controls-2 bx-clearfix">
+        <a class="bx-btn" href="javascript:void(0);" onclick="bx_classes_reorder_modules('__profile_id__', true)">Rearrange Moodules</a>
+        <a class="bx-btn bx-def-margin-left" href="javascript:void(0);" onclick="bx_classes_reorder_classes('__profile_id__', true)">Rearrange Classes</a>
+        <a class="bx-btn bx-def-margin-left bx-classes-btn-done" href="javascript:void(0);" onclick="bx_classes_reorder_classes('__profile_id__', false); bx_classes_reorder_modules('__profile_id__', false);">Done</a>
+    </div>
+</div>
+<div class="bx-course-classes">
+    __form__
+</div>

+ 22 - 0
modules/boonex/classes/template/css/main.css

@@ -1 +1,23 @@
 @import url(../../../../base/text/template/css/main.css);
+
+.bx-course-controls-1 {
+    float:left;
+}
+
+.bx-course-controls-2 {
+    float:right;
+}
+
+.bx-course-classes .bx-form-input-wrapper-custom {
+    min-height: 1.2rem;
+}
+
+.bx-classes-btn-done {
+    display:none;
+}
+.bx-course-reordering-mode .bx-classes-btn-done {
+    display:block;
+}
+.bx-course-reordering-mode .bx-btn:not(.bx-classes-btn-done) {
+    display:none;
+}

+ 3 - 1
modules/boonex/posts/install/sql/enable.sql

@@ -167,8 +167,10 @@ INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title`, `designbo
 
 -- PAGES: add page block to profiles modules (trigger* page objects are processed separately upon modules enable/disable)
 SET @iPBCellProfile = 3;
+SET @iPBCellGroup = 4;
 INSERT INTO `sys_pages_blocks` (`object`, `cell_id`, `module`, `title`, `designbox_id`, `visible_for_levels`, `type`, `content`, `deletable`, `copyable`, `order`) VALUES
-('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_posts', '_bx_posts_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:25:"bx_posts_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
+('trigger_page_profile_view_entry', @iPBCellProfile, 'bx_posts', '_bx_posts_page_block_title_my_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_posts";s:6:"method";s:13:"browse_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:25:"bx_posts_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0),
+('trigger_page_group_view_entry', @iPBCellGroup, 'bx_classes', '_bx_files_page_block_title_group_entries', 11, 2147483647, 'service', 'a:3:{s:6:"module";s:8:"bx_files";s:6:"method";s:19:"browse_group_author";s:6:"params";a:2:{i:0;s:12:"{profile_id}";i:1;a:2:{s:8:"per_page";s:25:"bx_files_per_page_profile";s:13:"empty_message";b:0;}}}', 0, 0, 0);
 
 -- PAGE: service blocks
 

+ 0 - 1
modules/boonex/tasks/classes/BxTasksConfig.php

@@ -136,7 +136,6 @@ class BxTasksConfig extends BxBaseModTextConfig
             'OBJECT_MENU_ACTIONS_VIEW_ENTRY' => 'bx_tasks_view', // actions menu on view entry page
             'OBJECT_MENU_ACTIONS_VIEW_ENTRY_ALL' => 'bx_tasks_view_actions', // all actions menu on view entry page
             'OBJECT_MENU_ACTIONS_MY_ENTRIES' => 'bx_tasks_my', // actions menu on my entries page
-            'OBJECT_MENU_SUBMENU' => 'bx_tasks_submenu', // main module submenu
             'OBJECT_MENU_SUBMENU_VIEW_ENTRY' => 'bx_tasks_view_submenu', // view entry submenu
             'OBJECT_MENU_SUBMENU_VIEW_ENTRY_MAIN_SELECTION' => 'tasks-home', // first item in view entry submenu from main module submenu
             'OBJECT_MENU_SNIPPET_META' => 'bx_tasks_snippet_meta', // menu for snippet meta info

+ 0 - 20
modules/boonex/tasks/classes/BxTasksGridAdministration.php

@@ -1,20 +0,0 @@
-<?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 BxTasksGridAdministration extends BxBaseModTextGridAdministration
-{
-    public function __construct ($aOptions, $oTemplate = false)
-    {
-    	$this->MODULE = 'bx_tasks';
-        parent::__construct ($aOptions, $oTemplate);
-    }
-}
-
-/** @} */

+ 1 - 6
modules/boonex/tasks/install/sql/disable.sql

@@ -13,7 +13,7 @@ DELETE FROM `sys_pages_blocks` WHERE `module` = 'bx_tasks' OR `object` IN('bx_ta
 -- 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_submenu', 'bx_tasks_view_submenu', 'bx_tasks_snippet_meta', 'bx_tasks_my', 'bx_tasks_menu_manage_tools');
+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_my', 'bx_tasks_menu_manage_tools');
 
 -- PRIVACY 
 DELETE FROM `sys_objects_privacy` WHERE `object` = 'bx_tasks_allow_view_to';
@@ -40,11 +40,6 @@ DELETE FROM `sys_statistics` WHERE `name` LIKE 'bx_tasks%';
 -- CHARTS
 DELETE FROM `sys_objects_chart` WHERE `object` LIKE 'bx_tasks%';
 
--- GRIDS
-DELETE FROM `sys_objects_grid` WHERE `object` IN ('bx_tasks_administration', 'bx_tasks_common');
-DELETE FROM `sys_grid_fields` WHERE `object` IN ('bx_tasks_administration', 'bx_tasks_common');
-DELETE FROM `sys_grid_actions` WHERE `object` IN ('bx_tasks_administration', 'bx_tasks_common');
-
 -- UPLOADERS
 DELETE FROM `sys_objects_uploader` WHERE `object` LIKE 'bx_tasks_%';
 

+ 0 - 34
modules/boonex/tasks/install/sql/enable.sql

@@ -83,14 +83,6 @@ INSERT INTO `sys_pages_blocks`(`object`, `cell_id`, `module`, `title_system`, `t
 ('bx_tasks_context', 1, 'bx_tasks', '_bx_tasks_page_block_title_sys_entries_in_context', '_bx_tasks_page_block_title_entries_in_context', 11, 2147483647, 'service', 'a:2:{s:6:\"module\";s:8:\"bx_tasks\";s:6:\"method\";s:14:\"browse_context\";}', 0, 0, 1, 1),
 ('bx_tasks_context', 1, 'bx_tasks', '_bx_tasks_page_block_title_sys_calendar_in_context', '_bx_tasks_page_block_title_calendar_in_context', 11, 2147483647, 'service', 'a:4:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:8:"calendar";s:12:"ignore_cache";b:1;s:6:"params";a:1:{i:0;a:1:{s:10:"context_id";s:12:"{profile_id}";}}}', 0, 0, 1, 2);
 
--- PAGE: module manage all
-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_administration', '_bx_tasks_page_title_sys_manage_administration', '_bx_tasks_page_title_manage', 'bx_tasks', 5, 192, 1, 'tasks-administration', 'page.php?i=tasks-administration', '', '', '', 0, 1, 0, 'BxTasksPageBrowse', 'modules/boonex/tasks/classes/BxTasksPageBrowse.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_administration', 1, 'bx_tasks', '_bx_tasks_page_block_title_system_manage_administration', '_bx_tasks_page_block_title_manage', 11, 192, 'service', 'a:3:{s:6:\"module\";s:8:\"bx_tasks\";s:6:\"method\";s:12:\"manage_tools\";s:6:\"params\";a:1:{i:0;s:14:\"administration\";}}', 0, 1, 0);
-
-
 -- MENU: create task form attachments (link, photo, video, etc)
 
 INSERT INTO `sys_objects_menu`(`object`, `title`, `set_name`, `module`, `template_id`, `deletable`, `active`, `override_class_name`, `override_class_file`) VALUES 
@@ -161,11 +153,6 @@ INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `titl
 ('bx_tasks_view_submenu', 'bx_tasks', 'view-task', '_bx_tasks_menu_item_title_system_view_entry', '_bx_tasks_menu_item_title_view_entry_submenu_entry', 'page.php?i=view-task&id={content_id}', '', '', '', '', 2147483647, 0, 0, 1),
 ('bx_tasks_view_submenu', 'bx_tasks', 'view-task-comments', '_bx_tasks_menu_item_title_system_view_entry_comments', '_bx_tasks_menu_item_title_view_entry_submenu_comments', 'page.php?i=view-task-comments&id={content_id}', '', '', '', '', 2147483647, 0, 0, 2);
 
--- MENU: dashboard manage tools
-SET @iManageMenuOrder = (SELECT IFNULL(MAX(`order`), 0) FROM `sys_menu_items` WHERE `set_name`='sys_account_dashboard_manage_tools' LIMIT 1);
-INSERT INTO `sys_menu_items`(`set_name`, `module`, `name`, `title_system`, `title`, `link`, `onclick`, `target`, `icon`, `addon`, `submenu_object`, `visible_for_levels`, `active`, `copyable`, `order`) VALUES 
-('sys_account_dashboard_manage_tools', 'bx_tasks', 'tasks-administration', '_bx_tasks_menu_item_title_system_admt_tasks', '_bx_tasks_menu_item_title_admt_tasks', 'page.php?i=tasks-administration', '', '_self', 'tasks', 'a:2:{s:6:"module";s:8:"bx_tasks";s:6:"method";s:27:"get_menu_addon_manage_tools";}', '', 192, 1, 0, @iManageMenuOrder + 1);
-
 -- 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 
@@ -270,27 +257,6 @@ INSERT INTO `sys_objects_chart` (`object`, `title`, `table`, `field_date_ts`, `f
 ('bx_tasks_growth', '_bx_tasks_chart_growth', 'bx_tasks_tasks', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 1, 'BxDolChartGrowth', ''),
 ('bx_tasks_growth_speed', '_bx_tasks_chart_growth_speed', 'bx_tasks_tasks', 'added', '', 'status,status_admin', '', 1, @iMaxOrderCharts + 2, 'BxDolChartGrowthSpeed', '');
 
--- GRIDS: moderation tools
-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_administration', 'Sql', 'SELECT * FROM `bx_tasks_tasks` WHERE 1 ', 'bx_tasks_tasks', 'id', 'added', 'status_admin', '', 20, NULL, 'start', '', 'title,text', '', 'like', 'reports', '', 192, 'BxTasksGridAdministration', 'modules/boonex/tasks/classes/BxTasksGridAdministration.php');
-
-INSERT INTO `sys_grid_fields` (`object`, `name`, `title`, `width`, `translatable`, `chars_limit`, `params`, `order`) VALUES
-('bx_tasks_administration', 'checkbox', '_sys_select', '2%', 0, '', '', 1),
-('bx_tasks_administration', 'switcher', '_bx_tasks_grid_column_title_adm_active', '8%', 0, '', '', 2),
-('bx_tasks_administration', 'reports', '_sys_txt_reports_title', '5%', 0, '', '', 3),
-('bx_tasks_administration', 'title', '_bx_tasks_grid_column_title_adm_title', '25%', 0, '25', '', 4),
-('bx_tasks_administration', 'added', '_bx_tasks_grid_column_title_adm_added', '20%', 1, '25', '', 5),
-('bx_tasks_administration', 'author', '_bx_tasks_grid_column_title_adm_author', '20%', 0, '25', '', 6),
-('bx_tasks_administration', 'actions', '', '20%', 0, '', '', 7);
-
-
-INSERT INTO `sys_grid_actions` (`object`, `type`, `name`, `title`, `icon`, `icon_only`, `confirm`, `order`) VALUES
-('bx_tasks_administration', 'bulk', 'delete', '_bx_tasks_grid_action_title_adm_delete', '', 0, 1, 1),
-('bx_tasks_administration', 'single', 'edit', '_bx_tasks_grid_action_title_adm_edit', 'pencil-alt', 1, 0, 1),
-('bx_tasks_administration', 'single', 'delete', '_bx_tasks_grid_action_title_adm_delete', 'remove', 1, 1, 2),
-('bx_tasks_administration', 'single', 'settings', '_bx_tasks_grid_action_title_adm_more_actions', 'cog', 1, 0, 3),
-('bx_tasks_administration', 'single', 'audit_content', '_bx_tasks_grid_action_title_adm_audit_content', 'search', 1, 0, 4);
-
 -- UPLOADERS
 
 INSERT INTO `sys_objects_uploader` (`object`, `active`, `override_class_name`, `override_class_file`) VALUES

+ 0 - 4
modules/boonex/tasks/install/sql/install.sql

@@ -516,10 +516,6 @@ INSERT INTO `sys_objects_content_info` (`name`, `title`, `alert_unit`, `alert_ac
 ('bx_tasks', '_bx_tasks', 'bx_tasks', 'added', 'edited', 'deleted', '', ''),
 ('bx_tasks_cmts', '_bx_tasks_cmts', 'bx_tasks', 'commentPost', 'commentUpdated', 'commentRemoved', 'BxDolContentInfoCmts', '');
 
-INSERT INTO `sys_content_info_grids` (`object`, `grid_object`, `grid_field_id`, `condition`, `selection`) VALUES
-('bx_tasks', 'bx_tasks_administration', 'id', '', ''),
-('bx_tasks', 'bx_tasks_common', 'id', '', '');
-
 -- SEARCH EXTENDED
 INSERT INTO `sys_objects_search_extended` (`object`, `object_content_info`, `module`, `title`, `active`, `class_name`, `class_file`) VALUES
 ('bx_tasks', 'bx_tasks', 'bx_tasks', '_bx_tasks_search_extended', 1, '', ''),

+ 0 - 2
modules/boonex/tasks/install/sql/uninstall.sql

@@ -49,8 +49,6 @@ DELETE FROM `sys_objects_feature` WHERE `name` = 'bx_tasks';
 -- CONTENT INFO
 DELETE FROM `sys_objects_content_info` WHERE `name` IN ('bx_tasks', 'bx_tasks_cmts');
 
-DELETE FROM `sys_content_info_grids` WHERE `object` IN ('bx_tasks');
-
 -- SEARCH EXTENDED
 DELETE FROM `sys_objects_search_extended` WHERE `module` = 'bx_tasks';
 

+ 11 - 1
template/scripts/BxBaseFormView.php

@@ -70,6 +70,11 @@ class BxBaseFormView extends BxDolForm
      */
     protected $_bViewMode = false;
 
+    /**
+     * Show or not sections which have no fileds
+     */
+    protected $_bShowEmptySections = false;
+
     /**
      * Function name for generation close form section HTML.
      */
@@ -254,6 +259,11 @@ class BxBaseFormView extends BxDolForm
         ));
     }
 
+    function setShowEmptySections($b)
+    {
+        $this->_bShowEmptySections = $b;
+    }
+
     function setAjaxMode($bAjaxMode)
     {
         $this->_bAjaxMode = (bool)$bAjaxMode;
@@ -450,7 +460,7 @@ BLAH;
         $sFuncGenRow = isset($this->aParams['view_mode']) && $this->aParams['view_mode'] ? 'genViewRow' : 'genRow';
         foreach ($this->aInputs as $aInput) {
             if (!isset($aInput['visible_for_levels']) || self::isVisible($aInput)) {
-                if ('block_header' == $aInput['type']) {
+                if ('block_header' == $aInput['type'] && !$this->_bShowEmptySections) {
                     // don't show section with no fields or with empty fields
                     if ($sContHeader) {                        
                         if ($sContFields)