diff --git a/Courseware.php b/Courseware.php
index 700f929b5..fa866cec6 100755
--- a/Courseware.php
+++ b/Courseware.php
@@ -28,6 +28,8 @@ class Courseware extends StudIPPlugin implements StandardPlugin
*/
private $container;
+ public static $registered_blocks = [];
+
public function __construct()
{
parent::__construct();
@@ -45,6 +47,8 @@ public function __construct()
// set text-domain for translations in this plugin
bindtextdomain('courseware', dirname(__FILE__).'/locale');
+
+ \NotificationCenter::postNotification('CoursewareRegisterBlocks', \Context::getId());
}
public function getPluginname()
@@ -91,7 +95,7 @@ public function getTabNavigation($courseId)
);
$settingsUrl = PluginEngine::getURL($this, compact('cid'), 'courseware/settings', true);
$navigation->addSubnavigation(
- 'settings',
+ 'settings',
new Navigation(_cw('Einstellungen'), $settingsUrl)
);
$navigation->addSubnavigation(
@@ -176,7 +180,7 @@ public function getIconNavigation($courseId, $last_visit, $user_id)
seminar_id = :cid
AND
chdate >= :last_visit
- AND
+ AND
type NOT IN ('Courseware', 'Chapter', 'Subchapter', 'Section')
");
$stmt->bindParam(':cid', $courseId);
@@ -189,7 +193,7 @@ public function getIconNavigation($courseId, $last_visit, $user_id)
if ($plugin_manager->getPluginInfo('VipsPlugin') == null){
$vips = false;
}
- if($plugin_manager->getPlugin('VipsPlugin')){
+ if($plugin_manager->getPlugin('VipsPlugin')){
$version = $plugin_manager->getPluginManifest($plugin_manager->getPlugin('VipsPlugin')->getPluginPath())['version'];
if (version_compare('1.3',$version) > 0) {
$vips = false;
@@ -517,8 +521,8 @@ public static function deleteUserdata($user_id)
$stmt = $db->prepare('
DELETE FROM
- mooc_userprogress
- WHERE
+ mooc_userprogress
+ WHERE
user_id = :uid
');
$stmt->bindParam(':uid', $user_id);
@@ -526,10 +530,10 @@ public static function deleteUserdata($user_id)
$stmt = $db->prepare('
DELETE FROM
- mooc_fields
- WHERE
+ mooc_fields
+ WHERE
user_id = :uid
- AND
+ AND
(name = "visited" OR name = "lastSelected")
');
$stmt->bindParam(':uid', $user_id);
@@ -538,4 +542,13 @@ public static function deleteUserdata($user_id)
return $exec;
}
+ public static function addBlock($plugin_name, $rel_path)
+ {
+ $path = PluginEngine::getPlugin($plugin_name)->getPluginPath();
+
+ self::$registered_blocks[] = [
+ 'plugin' => $plugin_name,
+ 'path' => $path .'/'. $rel_path,
+ ];
+ }
}
diff --git a/assets/js/courseware.js b/assets/js/courseware.js
index b14fa8835..77a053114 100644
--- a/assets/js/courseware.js
+++ b/assets/js/courseware.js
@@ -3,6 +3,9 @@ import $ from 'jquery'
import Backbone from 'backbone'
import helper from './url'
import BlockModel from './block_model'
+import block_types from './block_types';
+import AuthorView from 'js/author_view'
+import StudentView from 'js/student_view'
import '../less/courseware.less'
@@ -31,7 +34,6 @@ import 'ImageMapBlock/js/ImageMapBlock'
import 'InteractiveVideoBlock/js/InteractiveVideoBlock'
import 'KeyPointBlock/js/KeyPointBlock'
import 'LinkBlock/js/LinkBlock'
-import 'OpenCastBlock/js/OpenCastBlock'
import 'PdfBlock/js/PdfBlock'
import 'PostBlock/js/PostBlock'
import 'ScrollyBlock/js/ScrollyBlock'
@@ -103,3 +105,5 @@ function patchBackbone() {
return (xhr !== false) ? xhr : Promise.reject(new Error('ModelError'));
};
}
+
+export {$, Backbone, AuthorView, StudentView, helper, block_types };
diff --git a/blocks/OpenCastBlock/css/opencast_block.less b/blocks/OpenCastBlock/css/opencast_block.less
deleted file mode 100644
index 7c5e6d45a..000000000
--- a/blocks/OpenCastBlock/css/opencast_block.less
+++ /dev/null
@@ -1,19 +0,0 @@
-@import '../../../assets/less/mixins';
-
-.OpenCastBlock {
- iframe {
- border: solid thin #ccc;
- }
- .cw-opencast-useocplayer-wrapper {
- width: 40em;
- height: unset;
- padding: 0.5em 0;
- display: inline-block;
- vertical-align: top;
-
- span.bold{
- font-weight: 600;
- }
- }
-
-}
diff --git a/blocks/OpenCastBlock/js/OpenCastBlock.js b/blocks/OpenCastBlock/js/OpenCastBlock.js
deleted file mode 100644
index add812f27..000000000
--- a/blocks/OpenCastBlock/js/OpenCastBlock.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import block_types from 'js/block_types'
-import StudentView from './student_view'
-import AuthorView from './author_view'
-
-import '../css/opencast_block.less'
-
-export default block_types.add({
- name: 'OpenCastBlock',
-
- content_block: true,
-
- views: {
- student: StudentView,
- author: AuthorView
- }
-});
diff --git a/blocks/OpenCastBlock/js/author_view.js b/blocks/OpenCastBlock/js/author_view.js
deleted file mode 100644
index 24b75a322..000000000
--- a/blocks/OpenCastBlock/js/author_view.js
+++ /dev/null
@@ -1,109 +0,0 @@
-import $ from 'jquery'
-import Backbone from 'backbone'
-import AuthorView from 'js/author_view'
-import helper from 'js/url'
-
-export default AuthorView.extend({
-
- events: {
- 'click button[name=save]': 'onSave',
- 'click button[name=cancel]': 'switchBack'
- },
-
- initialize() {
- Backbone.on('beforemodeswitch', this.onModeSwitch, this);
- Backbone.on('beforenavigate', this.onNavigate, this);
- },
-
- render() {
- return this;
- },
-
- postRender() {
- let $opencast_id = this.$('.cw-opencast-stored-id').val();
- let $opencast_player = this.$('.cw-opencast-stored-player').val();
- if ($opencast_id != '') {
- this.$('.cw-opencast-content option[data-opencastid="'+$opencast_id+'"]').prop('selected', true);
- }
- switch($opencast_player){
- case 'treu':
- case 'theodul':
- default:
- this.$('.cw-opencast-useocplayer[value="theodul"]').prop('checked', true);
- break;
- case 'paella':
- this.$('.cw-opencast-useocplayer[value="paella"]').prop('checked', true);
- break;
- case 'false':
- this.$('.cw-opencast-useocplayer[value="false"]').prop('checked', true);
- break;
- }
-
- return this;
- },
-
- onNavigate(event) {
- if (!$('section .block-content button[name=save]').length) {
- return;
- }
- if(event.isUserInputHandled) {
- return;
- }
- event.isUserInputHandled = true;
- Backbone.trigger('preventnavigateto', !confirm('Es gibt nicht gespeicherte Änderungen. Möchten Sie die Seite trotzdem verlassen?'));
- },
-
- onModeSwitch(toView, event) {
- if (toView != 'student') {
- return;
- }
- // the user already switched back (i.e. the is not visible)
- if (!this.$el.is(':visible')) {
- return;
- }
- // another listener already handled the user's feedback
- if (event.isUserInputHandled) {
- return;
- }
- event.isUserInputHandled = true;
- Backbone.trigger('preventviewswitch', !confirm('Es gibt nicht gespeicherte Änderungen. Möchten Sie trotzdem fortfahren?'));
- },
-
- onSave(event) {
- var $view = this;
- let $opencast_content = {};
- $opencast_content.id = this.$(".cw-opencast-content option:selected").attr('data-opencastid');
- $opencast_content.useplayer = this.$('.cw-opencast-useocplayer:checked').val();
- $opencast_content.title = this.$(".cw-opencast-content option:selected").attr('data-episodetitle');
-
- switch($opencast_content.useplayer) {
- case 'theodul':
- default:
- $opencast_content.url_opencast_theodul = this.$(".cw-opencast-content option:selected").attr('data-urlopencasttheodul');
- break;
- case 'paella':
- $opencast_content.url_opencast_paella = this.$(".cw-opencast-content option:selected").attr('data-urlopencastpaella');
- break;
- case 'false':
- $opencast_content.url_mp4 = this.$(".cw-opencast-content option:selected").attr('data-urlmp4');
- break;
- }
- $opencast_content = JSON.stringify($opencast_content);
- helper
- .callHandler(this.model.id, 'save', {
- opencast_content : $opencast_content
- })
- .then(
- // success
- function () {
- $(event.target).addClass('accept');
- $view.switchBack();
- },
-
- // error
- function (error) {
- console.log(error);
- }
- );
- }
-});
diff --git a/blocks/OpenCastBlock/js/student_view.js b/blocks/OpenCastBlock/js/student_view.js
deleted file mode 100644
index 4971c0354..000000000
--- a/blocks/OpenCastBlock/js/student_view.js
+++ /dev/null
@@ -1,33 +0,0 @@
-import $ from 'jquery'
-import StudentView from 'js/student_view'
-import helper from 'js/url'
-
-export default StudentView.extend({
- events: {
- },
-
- initialize() { },
-
- render() {
- return this;
- },
-
- postRender() {
- try {
- OC.ltiCall(OC_SEARCH_URL, OC_LTI_DATA, function() {
- jQuery('iframe.courseware-oc-video').each(function() {
- this.src = this.dataset.src;
- });
- });
- } catch (e) {
- if (e instanceof ReferenceError) {
- console.log('OpenCast is not available');
- } else {
- console.log(e);
- }
- }
-
- return this;
- },
-
-});
diff --git a/blocks/OpenCastBlock/schema/opencast-1.0.xsd b/blocks/OpenCastBlock/schema/opencast-1.0.xsd
deleted file mode 100644
index 558400345..000000000
--- a/blocks/OpenCastBlock/schema/opencast-1.0.xsd
+++ /dev/null
@@ -1,8 +0,0 @@
-
-
-
-
{{content}}
diff --git a/blocks/OpenCastBlock/templates/student_view.mustache b/blocks/OpenCastBlock/templates/student_view.mustache deleted file mode 100644 index edcfcf308..000000000 --- a/blocks/OpenCastBlock/templates/student_view.mustache +++ /dev/null @@ -1,23 +0,0 @@ -{{#oc_present}} - - {{#url_isset}} - {{#useplayer}} - - - - {{/useplayer}} - {{^useplayer}} - - {{/useplayer}} - {{/url_isset}} - {{^url_isset}} - - {{/url_isset}} -{{/oc_present}} diff --git a/controllers/courseware.php b/controllers/courseware.php index 4ecce9519..60d792cc4 100755 --- a/controllers/courseware.php +++ b/controllers/courseware.php @@ -57,7 +57,7 @@ public function settings_action() return $this->redirect('courseware/settings'); } } - + public function news_action() { PageLayout::addStylesheet($this->plugin->getPluginURL().'/assets/static/courseware.css'); @@ -72,7 +72,7 @@ public function news_action() seminar_id = :cid AND chdate >= :last_visit - AND + AND type NOT IN ('Courseware', 'Chapter', 'Subchapter', 'Section') "); $stmt->bindParam(":cid", $this->container['cid']); @@ -86,7 +86,7 @@ public function news_action() if ($plugin_manager->getPluginInfo('VipsPlugin') == null){ $vips = false; } - if($plugin_manager->getPlugin('VipsPlugin')){ + if($plugin_manager->getPlugin('VipsPlugin')){ $version = $plugin_manager->getPluginManifest($plugin_manager->getPlugin('VipsPlugin')->getPluginPath())['version']; if (version_compare('1.3',$version) > 0) { $vips = false; @@ -99,20 +99,20 @@ public function news_action() // getting all tests $db = DBManager::get(); $stmt = $db->prepare(" - SELECT - json_data - FROM + SELECT + json_data + FROM mooc_blocks - JOIN - mooc_fields - ON - mooc_blocks.id = mooc_fields.block_id - WHERE + JOIN + mooc_fields + ON + mooc_blocks.id = mooc_fields.block_id + WHERE mooc_blocks.type = 'TestBlock' AND mooc_blocks.seminar_id = :cid - AND - mooc_fields.name = 'test_id' + AND + mooc_fields.name = 'test_id' "); $stmt->bindParam(":cid", $this->container['cid']); $stmt->execute(); @@ -166,7 +166,7 @@ public function news_action() $subchapter = $block->parent->parent->title; $section = $block->parent->title; if (!$block->isVisible()) {continue;} - $class_name = 'Mooc\UI\\'.$block->type.'\\'.$block->type; + $class_name = 'Mooc\UI\\'.$block->type.'\\'.$block->type; $name_constant = $class_name.'::NAME'; if (defined($name_constant)) { @@ -176,13 +176,13 @@ public function news_action() } $ui_block = $this->plugin->getBlockFactory()->makeBlock($block); $this->new_content[$chapter][$subchapter][$section][$block->id] = array( - 'title' => $title, + 'title' => $title, 'type' => $block->type, 'id' => $block->id, - 'ui_block' => $ui_block + 'ui_block' => $ui_block ); } - + return true; } @@ -196,7 +196,36 @@ private function getMustacheTemplates() { $templates = array(); - foreach (glob($this->plugin->getPluginPath() . '/blocks/*/templates/*.mustache') as $file) { + // add templates and load less files from block plugins + $plugin_template_files = array(); + + foreach (\Courseware::$registered_blocks as $block) { + $plugin_template_files = array_merge( + $plugin_template_files, + glob($block['path'] . '/templates/*.mustache') + ); + + // add stylesheets for block to page + foreach (glob($block['path'] . '/css/*.css') as $source) { + PageLayout::addHeadElement('link', [ + 'rel' => 'stylesheet', + 'type' => 'text/css', + 'href' => UrlHelper::getURL($source, ['cid' => null]) + ]); + } + + // add base js for block to page + PageLayout::addHeadElement('script', [ + 'src' => URLHelper::getUrl($block['path'] .'/js/'. basename($block['path']) .'.js'), + 'type' => 'module' + ], ''); + } + + // add base templates, integrating plugin templates + foreach (array_merge( + glob($this->plugin->getPluginPath() . '/blocks/*/templates/*.mustache'), + $plugin_template_files + ) as $file) { preg_match('|blocks/([^/]+)/templates/([^/]+).mustache$|', $file, $matches); list(, $block, $name) = $matches; @@ -263,7 +292,7 @@ private function storeSettings() // Scrollytelling // //////////////////////// $this->storeScrollytelling(isset($courseware_settings['scrollytelling']) ? true : false); - + //////////////////////// // EDITING PERMISSION // //////////////////////// @@ -320,7 +349,7 @@ private function storeDiscussionBlockActivation($active) // TODO: send a message back } } - + private function storeVipsTabVisible($active) { if (!$this->courseware_block->setVipsTabVisible($active)) { diff --git a/models/mooc/ui/BlockFactory.php b/models/mooc/ui/BlockFactory.php index 6baf2bdf3..6a64dc692 100755 --- a/models/mooc/ui/BlockFactory.php +++ b/models/mooc/ui/BlockFactory.php @@ -27,6 +27,8 @@ public function __construct(Container $container) */ public function makeBlock($sorm_block) { + $this->getBlockClasses(); + $class = 'Mooc\\UI\\'.$sorm_block->type.'\\'.$sorm_block->type; // there is no class describing a UI for that kind of block @@ -42,11 +44,23 @@ public function makeBlock($sorm_block) public function getBlockClasses() { static $classes; + if (!isset($classes)) { $classes = array_map("basename", glob($this->getPluginDir() . '/blocks/*')); } - return $classes; + $dyn_classes = []; + + foreach (\Courseware::$registered_blocks as $block) { + $dyn_classes[] = basename($block['path']); + + // load classes in blocks + foreach (glob($block['path'] . '/*.php') as $class) { + require_once($class); + } + } + + return array_merge($classes, $dyn_classes); } // TODO diff --git a/webpack.config.js b/webpack.config.js index 5af718bf7..6d7e30222 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -17,7 +17,8 @@ module.exports = { chunkFilename: '[name].chunk.js', filename: '[name].js', pathinfo: !isProd, - publicPath: !isProd ? 'http://localhost:8081/' : undefined + publicPath: !isProd ? 'http://localhost:8081/' : undefined, + library: '[name]' }, module: { rules: [