From d556145afcfe0dae3885f726a1f1963989bd2fe5 Mon Sep 17 00:00:00 2001 From: Richard Tibbles Date: Mon, 5 Mar 2018 14:30:27 -0800 Subject: [PATCH 1/2] First pass integration of Kolibri content renderers. --- contentcuration/contentcuration/apps.py | 2 + contentcuration/contentcuration/settings.py | 13 +- .../static/js/edit_channel/preview/views.js | 157 ++++++++++++------ .../static/js/edit_channel/sync/views.js | 10 +- .../templates/channel_edit.html | 4 + requirements.txt | 1 + 6 files changed, 134 insertions(+), 53 deletions(-) diff --git a/contentcuration/contentcuration/apps.py b/contentcuration/contentcuration/apps.py index 4418641769..39409fedd1 100644 --- a/contentcuration/contentcuration/apps.py +++ b/contentcuration/contentcuration/apps.py @@ -1,6 +1,7 @@ import os from django.apps import AppConfig from django.conf import settings +from kolibri.plugins.registry import initialize class ContentConfig(AppConfig): @@ -11,3 +12,4 @@ def ready(self): os.makedirs(settings.STORAGE_ROOT) except os.error: pass + initialize() diff --git a/contentcuration/contentcuration/settings.py b/contentcuration/contentcuration/settings.py index 18ad36f3fa..7c3b562152 100644 --- a/contentcuration/contentcuration/settings.py +++ b/contentcuration/contentcuration/settings.py @@ -25,6 +25,8 @@ STATIC_ROOT = os.path.join(BASE_DIR, "static") DB_ROOT = os.path.join(BASE_DIR, "databases") +KOLIBRI_CORE_JS_NAME = 'kolibriGlobal' + PERMISSION_TEMPLATE_ROOT = os.path.join(BASE_DIR, "contentcuration", "templates", "permissions") # Quick-start development settings - unsuitable for production @@ -56,7 +58,12 @@ 'email_extras', 'le_utils', 'rest_framework.authtoken', - 'search' + 'search', + 'kolibri.core', + 'kolibri.plugins.media_player', + 'kolibri.plugins.document_pdf_render', + 'kolibri_exercise_perseus_plugin', + 'kolibri.plugins.html5_app_renderer', ) SESSION_ENGINE = "django.contrib.sessions.backends.cached_db" @@ -113,6 +120,10 @@ 'django.contrib.auth.context_processors.auth', 'django.contrib.messages.context_processors.messages', ], + 'libraries': { + 'kolibri_tags': 'kolibri.core.webpack.templatetags.webpack_tags', + 'content_tags': 'kolibri.content.templatetags.content_tags', + }, }, }, ] diff --git a/contentcuration/contentcuration/static/js/edit_channel/preview/views.js b/contentcuration/contentcuration/static/js/edit_channel/preview/views.js index 29caa95365..1a418b75ea 100644 --- a/contentcuration/contentcuration/static/js/edit_channel/preview/views.js +++ b/contentcuration/contentcuration/static/js/edit_channel/preview/views.js @@ -40,6 +40,7 @@ var PreviewView = BaseViews.BaseView.extend({ initialize: function(options) { _.bindAll(this, 'select_preview','toggle_fullscreen', 'load_preview', 'exit_fullscreen', 'render_preview'); this.current_preview = null; + this.previewView = null; this.render(); }, events: { @@ -100,14 +101,21 @@ var PreviewView = BaseViews.BaseView.extend({ }, generate_preview:function(force_load){ if(this.current_preview){ - _.defer(render_preview, - this.$("#preview_window"), - this.current_preview, - this.get_subtitles(), - force_load && this.model.get('kind') === "video", - this.model.get("thumbnail_encoding") && this.model.get("thumbnail_encoding").base64, - this.get_intl_data() - ); + var data = { + content_model: this.model, + file_model: this.current_preview, + subtitles: this.get_subtitles(), + force_load: force_load && this.model.get('kind') === "video", + encoding: this.model.get("thumbnail_encoding") && this.model.get("thumbnail_encoding").base64, + intl_data: this.get_intl_data() + }; + if (!this.previewView) { + data.el = this.$("#preview_window"); + this.previewView = new ItemPreviewView(data); + } else { + this.previewView.setData(data); + } + this.previewView.render(); } }, get_subtitles:function(){ @@ -172,52 +180,99 @@ var PreviewView = BaseViews.BaseView.extend({ } }); -function render_preview(el, file_model, subtitles, force_load, encoding, intl_data){ - var preview_template; - var source = file_model.storage_url; - switch (file_model.file_format){ - case "png": - case "jpg": - case "jpeg": - source = encoding || source; - preview_template = require("./hbtemplates/preview_templates/image.handlebars"); - break; - case "pdf": - case "PDF": - case "vtt": - case "srt": - preview_template = require("./hbtemplates/preview_templates/document.handlebars"); - break; - case "mp3": - preview_template = require("./hbtemplates/preview_templates/audio.handlebars"); - break; - case "mp4": - preview_template = require("./hbtemplates/preview_templates/video.handlebars"); - break; - case "perseus": - preview_template = require("./hbtemplates/preview_templates/exercise.handlebars"); - break; - case "zip": - preview_template = require("./hbtemplates/preview_templates/html5.handlebars"); - break; - default: - preview_template = require("./hbtemplates/preview_templates/default.handlebars"); - } - el.html(preview_template({ - source: source, - extension:file_model.mimetype, - checksum:file_model.checksum, - subtitles : subtitles - }, { - data: intl_data - })); - if(force_load){ - el.find("video").load(); +var ItemPreviewView = BaseViews.BaseView.extend({ + initialize: function(options) { + _.bindAll(this, 'render', 'cleanUpVuePreview'); + this.vuePreview = null; + this.setData(options); + this.render(); + }, + setData: function (options) { + this.content_model = options.content_model; + this.file_model = options.file_model; + this.subtitles = options.subtitles; + this.force_load = options.force_load; + this.encoding = options.encoding; + this.intl_data = options.intl_data; + }, + render: function () { + var preview_template; + var source = this.file_model.storage_url; + switch (this.file_model.file_format){ + case "png": + case "jpg": + case "jpeg": + source = this.encoding || source; + preview_template = require("./hbtemplates/preview_templates/image.handlebars"); + break; + case "vtt": + case "srt": + preview_template = require("./hbtemplates/preview_templates/document.handlebars"); + break; + case "pdf": + case "PDF": + case "mp3": + case "mp4": + case "perseus": + case "zip": + break; + default: + preview_template = require("./hbtemplates/preview_templates/default.handlebars"); + } + if (preview_template) { + this.cleanUpVuePreview(); + this.$el.html(preview_template({ + source: source, + extension: this.file_model.mimetype, + checksum: this.file_model.checksum, + subtitles : this.subtitles + }, { + data: this.intl_data + })); + if(this.force_load){ + this.$el.find("video").load(); + } + } else { + var kind = this.content_model.get('kind'); + var propsData = { + kind: kind, + files: [{ + storage_url: source, + extension: this.file_model.file_format, + available: true, + }], + available: true, + assessment: kind === 'exercise', + interactive: false, + itemId: kind === 'exercise' ? this.content_model.get('assessment_item_ids')[0] : null + }; + if (!this.vuePreview) { + var ContentRendererComponent = Object.assign({}, window.kolibriGlobal.coreVue.components.contentRenderer); + var Vue = window.kolibriGlobal.lib.vue; + var ContentRenderer = Vue.extend(ContentRendererComponent); + if (!window.kolibriGlobal.coreVue.vuex.store.default.__initialized) { + window.kolibriGlobal.coreVue.vuex.store.default.registerModule(); + } + this.vuePreview = new ContentRenderer({ + propsData: propsData, + el: this.$el[0], + store: window.kolibriGlobal.coreVue.vuex.store.default, + }); + } else { + Object.assign(this.vuePreview, propsData); + } + } + }, + cleanUpVuePreview: function() { + if (this.vuePreview) { + this.vuePreview.destroy(); + this.vuePreview = null; + } } -}; +}); module.exports = { PreviewModalView:PreviewModalView, PreviewView:PreviewView, - render_preview: render_preview + ItemPreviewView: ItemPreviewView } diff --git a/contentcuration/contentcuration/static/js/edit_channel/sync/views.js b/contentcuration/contentcuration/static/js/edit_channel/sync/views.js index 4fa874453a..fd229e9412 100644 --- a/contentcuration/contentcuration/static/js/edit_channel/sync/views.js +++ b/contentcuration/contentcuration/static/js/edit_channel/sync/views.js @@ -524,7 +524,15 @@ var SyncPreviewFileView = SyncPreviewModalView.extend({ }, create_preview: function(){ var previewer = require('edit_channel/preview/views'); - previewer.render_preview(this.$("#preview_window"), this.model, this.subtitles, true, this.node.get('thumbnail_encoding') && this.node.get("thumbnail_encoding").base64, this.get_intl_data()); + previewer.ItemPreviewView({ + el: this.$("#preview_window"), + content_model: this.node, + file_model: this.model, + subtitles: this.subtitles, + force_load: true, + encoding: this.node.get('thumbnail_encoding') && this.node.get("thumbnail_encoding").base64, + intl_data: this.get_intl_data() + }).render(); if(this.subtitles.length){ this.$("#preview_window video").get(0).textTracks[0].mode = "showing"; } diff --git a/contentcuration/contentcuration/templates/channel_edit.html b/contentcuration/contentcuration/templates/channel_edit.html index ffcc6205af..aab7d84fb8 100644 --- a/contentcuration/contentcuration/templates/channel_edit.html +++ b/contentcuration/contentcuration/templates/channel_edit.html @@ -2,6 +2,8 @@ {% extends "base.html" %} {% load staticfiles %} {% load i18n %} +{% load kolibri_tags %} +{% load content_tags %} {% block content %} @@ -78,4 +80,6 @@
+ {% webpack_asset 'default_frontend' %} + {% content_renderer_assets %} {% endblock content %} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 4dee4a5d33..ac32478d13 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,6 +15,7 @@ django-hashedfilenamestorage==1.0.0 djangorestframework-bulk==0.2.1 django-email-extras==0.3.3 kolibri==0.7.0 +kolibri-exercise-perseus-plugin==0.7.4 validators le-utils>=0.1.9 gunicorn==19.6.0 From 784006707126c58be2ec4f5a61db76c385ac930a Mon Sep 17 00:00:00 2001 From: Richard Tibbles Date: Tue, 10 Apr 2018 17:58:12 -0700 Subject: [PATCH 2/2] Setup a KOLIBRI HOME os var for our kolibri package. --- contentcuration/manage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/contentcuration/manage.py b/contentcuration/manage.py index ed7fe04522..cec67d2a81 100755 --- a/contentcuration/manage.py +++ b/contentcuration/manage.py @@ -2,6 +2,9 @@ import os import sys +os.environ.setdefault( + "KOLIBRI_HOME", os.path.join(os.path.expanduser("~"), ".kolibri") +) # Attach Python Cloud Debugger if __name__ == "__main__":