文档章节

xblock-sdk学习笔记之制作studio界面

DatoChen
 DatoChen
发布于 2015/03/09 22:14
字数 1881
阅读 51
收藏 0
点赞 0
评论 0

本文首发与我的博客莲花乡—十里屯。 由于公司采用TEAM@OSC管理项目,为了方便交流转载至此。

#使用studio自带的文本编辑器 如果我们使用过studio的话不难看出它使用的是tinyMCE。如此问题就好解决了,我们只要定义一个textarea控件,在JS中将其初始化成在线编辑器就可以了,大致代码如下:
先给出模板代码:
<!-- lang: html --> <!-- editor --> <div class="wrapper-comp-editor is-active is-set" id="editor-tab" data-editor="visual"> <section class="html-editor editor"> <div><span>Please input the topic request:</span></div> <div class="row"><textarea class="tiny-mce" name="editor_question" id="editor_question">{question}</textarea></div> </section> </div> 相应的JS代码:
<!-- lang: js --> tinymce.init({ selector: "#editor-tab .tiny-mce", skin: 'studio-tmce4', height:"300", formats: {code: {inline: 'code'} }, codemirror: {path: "/static/js/vendor"}, plugins: "image link codemirror media", menubar: false, toolbar_items_size: 'small', extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]", toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media | code ", resize: "both" }); #创建tab选项卡 这个功能我想了很久,本来以为很简单,直接在templates中编写一个tabs就可以了。后来发现不行,因为写的两个div都是在<div class="modal-content"></div>中而正常情况下,标签代码应该在<div class="modal-header"></div>中,内容在<div class="modal-content"></div>中。如此才能正好利用上studio中原有的css和js代码。 最初想的解决方法是在js中动态为相应的div填充内容。后来感觉上这样做不够合理,应该有其它的解决方案,最后分析了 html组件中的文本输入组件才发现只要将设置页面的div增加 metadata_edit 这个class即可实现tab选项卡的功能。
<!-- lang: html --> <!-- settings --> <div class="wrapper-comp-settings metadata_edit" id="settings-tab"> <ul class="list-input settings-list metadata_entry"> <li class="field comp-setting-entry metadata_entry"> <div class="wrapper-comp-setting"> <label class="label setting-label" for="module_title">display name</label> <input class="input setting-input" type="text" name="module_title" value="{module_title}"> </div> <span class="tip setting-help">tips: ......</span> </li>

        <li class="field comp-setting-entry metadata_entry">
            <div class="wrapper-comp-setting">
                <label class="label setting-label" for="editor_type">Editor</label>
                <select class="input setting-input" name="editor_type">
                            <option value="visual">visual</option>
                            <option value="org">org</option>
                </select>
            </div>
            <span class="tip setting-help">tips: ......</span>
        </li>
  </ul>
</div>

如此,在测试时发现,我们填写的设置选项没有任何效果。在浏览器中调试,js报错为:Failed to load metadata-editor template。再进一步跟踪就会发现是在/cms/templates/widgets/metadata-edit.html 模板中加载:/cms/templates/js/metadata-editor.underscore 文件时加载失败了。其文件代码如下:

<!-- lang: html -->
## js templates
<script id="metadata-editor-tpl" type="text/template">
    <%static:include path="js/metadata-editor.underscore" />
</script>

...

<div class="wrapper-comp-settings metadata_edit" id="settings-tab" data-metadata='${json.dumps(metadata_field_copy, cls=EdxJSONEncoder) | h}'/>

对应的 underscore 文件内容:
<!-- lang: html --> <ul class="list-input settings-list"> <% .each(.range(numEntries), function() { %> <li class="field comp-setting-entry metadata_entry"> </li> <% }) %> </ul> 如此,我们再将我们的template内容改写一下:

<!-- lang: html -->
<!-- element -->
<script id="metadata-editor-tpl" type="text/template">
  <ul class="list-input settings-list metadata_entry">
        <li class="field comp-setting-entry metadata_entry">
            <div class="wrapper-comp-setting">
                <label class="label setting-label" for="module_title">display name</label>
                <input class="input setting-input" type="text" name="module_title" value="{module_title}">
            </div>
            <span class="tip setting-help">tips: ......</span>
        </li>

        <li class="field comp-setting-entry metadata_entry">
            <div class="wrapper-comp-setting">
                <label class="label setting-label" for="editor_type">Editor</label>
                <select class="input setting-input" name="editor_type">
                            <option value="visual">visual</option>
                            <option value="org">org</option>
                </select>
            </div>
            <span class="tip setting-help">tips: ......</span>
        </li>
  </ul>

</script>

<!-- editor -->
<div class="wrapper-comp-editor is-active is-set" id="editor-tab" data-editor="visual">
    <section class="html-editor editor">
        <div><span>Please input the topic request:</span></div>
        <div class="row"><textarea class="tiny-mce" name="editor_question" id="editor_question">{question}</textarea></div>
    </section>
</div>

<!-- settings  -->
<div class="wrapper-comp-settings metadata_edit" id="settings-tab"></div>

#使用studio自带的保存和取消按钮 这个问题在github和googlegroup上有好些人都在问,网上现有的比较通用的处理方法是在<div class="modal-content"></div>中自定义一个保存和取消按钮,在JS中处理(可以参考:https://groups.google.com/forum/#!searchin/edx-code/xblock$20save/edx-code/l246xiaiGAc/TYTrQX0MvPUJ 和 本文最后的参考资料中的处理方式)。直到后来制作tab页面时才发现自定义的保存、取消按钮会受到选项卡切换的影响。用firebug查看了整个页面的html才知道,页面中原本是有保存和取消按钮的只是被隐藏,不显示而已。 我最初的解决方法是在js中强行控制 <div class="modal-actions"></div> 中的元素,强行令其显示,后来在做选项卡之后发现了新的bug。有js将保存按钮隐藏,将取消按钮的title改成OK了。经过一番折腾调试,发现罪魁祸首是:/static/js/views/modals/edit_xblock.js,相关代码如下:
<!-- lang: js --> onDisplayXBlock: function() { var editorView = this.editorView, title = this.getTitle();

    // Notify the runtime that the modal has been shown
    editorView.notifyRuntime('modal-shown', this);

    // 是否启用自定义的tab控件
    if (editorView.hasCustomTabs()) {
        // Hide the modal's header as the custom editor provides its own
        this.$('.modal-header').hide();

        // Update the custom editor's title
        editorView.$('.component-name').text(title);
    } else {
        this.$('.modal-window-title').text(title);
        if (editorView.getDataEditor() && editorView.getMetadataEditor()) {
            this.addDefaultModes();
            this.selectMode(editorView.mode);
        }
    }

    // 是否使用自定义的动作按钮
    if (!editorView.hasCustomButtons()) {
        // 如果当前的xblock插件不支持保存功能,就禁用保存按钮。
        if (!editorView.xblock.save) {
            this.disableSave();
        }
        this.getActionBar().show();
    }

    // Resize the modal to fit the window
    this.resize();
},

// 禁用保存按钮
disableSave: function() {
    var saveButton = this.getActionButton('save'),
        cancelButton = this.getActionButton('cancel');
    saveButton.hide();
    cancelButton.text(gettext('OK'));
    cancelButton.addClass('action-primary');
},

这代码的意思很明显是说,该xblock插件不支持save方法。根据栈回朔,定位到相关代码如下:

<!-- lang: js -->
handleXBlockFragment: function(fragment, options) {
    var self = this,
        wrapper = this.$el,
        xblockElement,
        successCallback = options ? options.success || options.done : null,
        errorCallback = options ? options.error || options.done : null,
        xblock,
        fragmentsRendered;
    
    fragmentsRendered = this.renderXBlockFragment(fragment, wrapper);
    fragmentsRendered.always(function() {
        // 这里得到我们自定义xblock插件的dom对象
        xblockElement = self.$('.xblock').first();
        try {
            // 初始化操作,其实就是进去调用我们xblock的js方法,我们可以跟进看一下
            xblock = XBlock.initializeBlock(xblockElement);
            self.xblock = xblock;
            self.xblockReady(xblock);
            if (successCallback) {
                successCallback(xblock);
            }
        } catch (e) {
            console.error(e.stack);
            // Add 'xblock-initialization-failed' class to every xblock
            self.$('.xblock').addClass('xblock-initialization-failed');
    
            // If the xblock was rendered but failed then still call xblockReady to allow
            // drag-and-drop to be initialized.
            if (xblockElement) {
                self.xblockReady(null);
            }
            if (errorCallback) {
                errorCallback();
            }
        }
    });

查看 XBlock.initializeBlock 的定义:/common/static/coffee/src/xblock/core.coffee:10
<!-- lang: js --> initializeBlock: (element, requestToken) -> $element = $(element) requestToken = requestToken or $element.data('request-token') children = @initializeBlocks($element, requestToken) runtime = $element.data("runtime-class") version = $element.data("runtime-version") initFnName = $element.data("init") $element.prop('xblock_children', children) if runtime? and version? and initFnName? # 根据相应版本获取我们方法的名称 runtime = new window[runtime]["v#{version}"] initFn = window[initFnName] # 调用我们自定义的方法,例如我指定的方法名是: frag.initialize_js('SubjectiveEditBlock') # 此方法是有返回值的,返回一个 类似capa中名后缀为 Descriptor 的xblock对象, 如果没有返回值就是一个空对象。 block = initFn(runtime, element) ? {} block.runtime = runtime else elementTag = $('<div>').append($element.clone()).html(); console.log("Block #{elementTag} is missing data-runtime, data-runtime-version or data-init, and can't be initialized") block = {}

  block.element = element
  block.name = $element.data("name")

  $element.trigger("xblock-initialized")
  $element.data("initialized", true)
  $element.addClass("xblock-initialized")
  block

到这里一切就都很明了了,我们只要让我们自定义的xblock方法返回一个对象,该对象中包含save方法即可,代码大致如下:
<!-- lang: js --> // 返回一个自定义对象,其需要有save方法 function SubjectiveEditDescriptor(){ }

function SubjectiveEditBlock(runtime, element) {
    // 为返回的对象命名,具体请参考 /common/static/coffee/src/xblock/core.coffee:10
    $(element).data('name', 'SubjectiveEditDescriptor');

    var subjectiveEditDescriptor = new SubjectiveEditDescriptor();
    
    // 定义save方法
    subjectiveEditDescriptor.save = function(){
        var handlerUrl = runtime.handlerUrl(element, 'studio_submit');
        var data = {
            module_title: $(element).find('input[name=module_title]').val(),
            editor_type: $(element).find('input[name=editor_type]').val(),
            editor_question: tinyMCE.activeEditor.getContent()
        };

        $.post(handlerUrl, JSON.stringify(data)).done(function(response) {
            window.location.reload(false);
        });
    };

    tinymce.init({
                selector: "#editor-tab .tiny-mce",
                skin: 'studio-tmce4',
                height:"300",
                formats: {code: {inline: 'code'}
            },
            codemirror: {path: "/static/js/vendor"},
            plugins: "image link codemirror media",
            menubar: false,
            toolbar_items_size: 'small',
            extended_valid_elements : "iframe[src|frameborder|style|scrolling|class|width|height|name|align|id]",
            toolbar: "insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | link image media | code ",
            resize: "both"
        });

    //  将对象返回
    return subjectiveEditDescriptor;
};

至此,Studio界面相关的分析结束。如果哪里有遗漏还望各位看官批评指正。最后上传几张效果图: 在此输入图片描述 在此输入图片描述 在此输入图片描述

#参考资料 1.XBlock 0.1 documentation - Tutorial 2.XBlock: Open edX courseware components 3.[开发] Open edX 56 网 XBlock 视频插件开发(基础)

© 著作权归作者所有

共有 人打赏支持
DatoChen
粉丝 2
博文 3
码字总数 2326
作品 0
青岛
程序员
android的学习笔记

知识记录 获取apk package path。 (aapt工具在文件夹里) 或者打开Android SDK manager,打开Android AVD manager。列出更多命令 android sdk manager只有Android 4.2.2的platform或者根本没...

前端届的科比
2015/09/05
52
0
Android开发资源推荐第2季

Android CPU监控想法,思路,核心技术和代码 http://www.csdn123.com/html/blogs/20131026/89017.htm Android App /Task/Stack 总体分析 http://www.eoeandroid.com/thread-161703-1-1.html......

eclipse_xu
2014/08/18
0
0
Android Studio2.x版本无法自动关联源码的解决方法

Android Studio2.x版本无法自动关联源码的解决方法 在学习android开发过程中,对于一个不熟悉的类,阅读源码是一个很好的学习方式,使用andorid studio开发工具的SDK Manager管理工具可以十分...

珲少
2016/08/20
283
0
张高兴的 Xamarin.Android 学习笔记:(一)环境配置

  最近在自学 Xamarin 和 Android ,同时发现国内在做 Xamarin 的不多。我在自学中间遇到了很多问题,而且百度到的很多教程也有些过时,现在打算写点东西稍微总结下,顺便帮后人指指路了。...

张高兴
2017/01/13
0
0
Silverlight 2.0学习笔记——XAML

XAML是在WPF应用程序中使用的UI标记语言,它是英文eXtensible Application Markup Language的缩写,它是基于XML标记语言的一种特殊格式。WPF运行时解释这些标记,显示UI界面,并且还可以集成...

长平狐
2012/10/16
64
0
Windows Phone开发(2):竖立自信,初试锋茫

上一篇文章中,我们聊了一些“大炮”话题,从这篇文章开始,我们一起来学习WP开发吧。 一、我们有哪些装备。 安装完VS 学习版 for WP后,也连同SDK一并安装了,不必像安卓那样,安装JDK,下载...

junwong
2012/04/18
1K
0
开发工具总结(7)之多年珍藏的Android开发必备网站和工具

【前言】工欲善其事,必先利其器。搞开发多年了,会收藏一些干货网站和工具,辅助开发,提高开发效率。下面一次性分享给大家。喜欢的朋友们点个赞吧。 说明:这些是我收藏的网站,感觉还是不...

AWeiLoveAndroid
01/08
0
0
Android Studio 之下载安装

目录[-] 背景 Android Studio VS Eclipse 下载 创建HelloWorld项目 背景 相信大家对Android Studio已经不陌生了,Android Studio是Google于2013 I/O大会针对Android开发推出的新的开发工具,...

码娃娃
2015/12/09
29
0
Android Studio 初步学习与配置

首先,在AS官网下载Android Studio的安装包,选择安装插件时勾选SDK和虚拟机。 然后一直next到选择安装路径,这里注意不要将AS安装到系统盘。 之后即可等待安装完成。 首次打开AS时需要选择相...

sysu_chan
04/15
0
0
【Android 开发入门】Android Studio 下载及安装

android 开发工具主流的还是Android Studio,当然也有很多人喜欢用Eclipse,也有人喜欢用IntelliJ IDEA ;还有Xamarin这种只需要编写一次代码,可以编译多种平台可运行的强大工具。但是它又真...

微wx笑
2016/09/11
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

about git flow

  昨天元芳做了git分支管理规范的分享,为了拓展大家关于git分支的认知,这里我特意再分享这两个关于git flow的链接,大家可以看一下。 Git 工作流程 Git分支管理策略   git flow本质上是...

qwfys
今天
2
0
Linux系统日志文件

/var/log/messages linux系统总日志 /etc/logrotate.conf 日志切割配置文件 参考https://my.oschina.net/u/2000675/blog/908189 dmesg命令 dmesg’命令显示linux内核的环形缓冲区信息,我们可...

chencheng-linux
今天
1
0
MacOS下给树莓派安装Raspbian系统

下载镜像 前往 树莓派官网 下载镜像。 点击 最新版Raspbian 下载最新版镜像。 下载后请,通过 访达 双击解压,或通过 unzip 命令解压。 检查下载的文件 ls -lh -rw-r--r-- 1 dingdayu s...

dingdayu
今天
1
0
spring boot使用通用mapper(tk.mapper) ,id自增和回显等问题

最近项目使用到tk.mapper设置id自增,数据库是mysql。在使用通用mapper主键生成过程中有一些问题,在总结一下。 1、UUID生成方式-字符串主键 在主键上增加注解 @Id @GeneratedValue...

北岩
今天
2
0
告警系统邮件引擎、运行告警系统

告警系统邮件引擎 cd mail vim mail.py #!/usr/bin/env python#-*- coding: UTF-8 -*-import os,sysreload(sys)sys.setdefaultencoding('utf8')import getoptimport smtplibfr......

Zhouliang6
今天
1
0
Java工具类—随机数

Java中常用的生成随机数有Math.random()方法及java.util.Random类.但他们生成的随机数都是伪随机的. Math.radom()方法 在jdk1.8的Math类中可以看到,Math.random()方法实际上就是调用Random类...

PrivateO2
今天
2
0
关于java内存模型、并发编程的好文

Java并发编程:volatile关键字解析    volatile这个关键字可能很多朋友都听说过,或许也都用过。在Java 5之前,它是一个备受争议的关键字,因为在程序中使用它往往会导致出人意料的结果。在...

DannyCoder
昨天
1
0
dubbo @Reference retries 重试次数 一个坑

在代码一中设置 成retries=0,也就是调用超时不用重试,结果DEBUG的时候总是重试,不是0吗,0就不用重试啊。为什么还是调用了多次呢? 结果在网上看到 这篇文章才明白 https://www.cnblogs....

奋斗的小牛
昨天
2
0
数据结构与算法3

要抓紧喽~~~~~~~放羊的孩纸回来喽 LowArray类和LowArrayApp类 程序将一个普通的Java数组封装在LowArray类中。类中的数组隐藏了起来,它是私有的,所以只有类自己的方法才能访问他。 LowArray...

沉迷于编程的小菜菜
昨天
1
0
spring boot应用测试框架介绍

一、spring boot应用测试存在的问题 官方提供的测试框架spring-boot-test-starter,虽然提供了很多功能(junit、spring test、assertj、hamcrest、mockito、jsonassert、jsonpath),但是在数...

yangjianzhou
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部