Commit 5d025fc4 by Sean Lip

Add the actual XBlock.

parent 5b260639
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
......@@ -178,7 +179,7 @@
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
......@@ -186,7 +187,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
......@@ -199,4 +200,3 @@
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
# oppia-xblock
Oppia XBlock for the OpenEdX platform
## Embedding Oppia explorations in the OpenEdX platform
This XBlock is packaged in the standard way as other third-party XBlock
contributions to the OpenEdX platform. The following notes are only
suggestions, but please note that the way XBlocks are installed may change over
time. If in doubt, consult the latest OpenEdX documentation.
Download the contents of this repository to a folder on your local machine, and deploy it following the
instructions in [this tutorial](http://opencraft.com/doc/edx/xblock/tutorial.html#deploying-to-edx-platform).
Note that you will need to add the value "oppia" to the `advanced_modules`
field in Studio's 'Advanced Settings' menu.
Notes:
(1) On devstack, the XBlock does not show up in Studio as a live preview in the
editor. However, it does show up in the LMS.
(2) If you wish to record events, you can do so by modifying the _log() method
in the oppia.py file.
from .oppia import OppiaXBlock
# coding: utf-8
#
# Copyright 2015 The Oppia Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""This XBlock embeds an instance of Oppia in the OpenEdX platform."""
import pkg_resources
from xblock.core import XBlock
from xblock.fields import Scope, Integer, String
from xblock.fragment import Fragment
class OppiaXBlock(XBlock):
"""
An XBlock providing an embedded Oppia exploration.
"""
# Note: These fields are defined on the class, and can be accessed in the
# code as self.<fieldname>.
oppiaid = String(
help="ID of the Oppia exploration to embed",
default=None,
scope=Scope.content)
src = String(
help="Source URL of the site",
default="https://www.oppia.org",
scope=Scope.content)
width = Integer(
help="Width of the embedded exploration",
default=700,
scope=Scope.content)
height = Integer(
help="Height of the embedded exploration",
default=500,
scope=Scope.content)
def resource_string(self, path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string(__name__, path)
return data.decode("utf8")
def student_view(self, context=None):
"""
The primary view of the OppiaXBlock, shown to students
when viewing courses.
"""
html = self.resource_string("static/html/oppia.html")
frag = Fragment(html.format(self=self))
frag.add_javascript_url(
"//cdn.jsdelivr.net/oppia/0.0.1/oppia-player.min.js")
frag.add_javascript(self.resource_string("static/js/oppia.js"))
frag.initialize_js('OppiaXBlock')
return frag
def _log(self, message):
"""
Logger for load, state transition and completion events.
"""
pass
@XBlock.json_handler
def on_exploration_loaded(self, data, suffix=''):
"""Called when an exploration has loaded."""
self._log('Exploration %s was loaded.' % self.oppiaid)
@XBlock.json_handler
def on_state_transition(self, data, suffix=''):
"""Called when a state transition in the exploration has occurred."""
self._log(
"Recording the following state transition for exploration %s: "
"'%s' to '%s'" % (
self.oppiaid, data['oldStateName'], data['newStateName']))
@XBlock.json_handler
def on_exploration_completed(self, data, suffix=''):
"""Called when the exploration has been completed."""
self._log('Exploration %s has been completed.' % self.oppiaid)
def studio_view(self, context):
"""
Create a fragment used to display the edit view in the Studio.
"""
html_str = pkg_resources.resource_string(
__name__, "static/html/oppia_edit.html")
oppiaid = self.oppiaid or ''
frag = Fragment(unicode(html_str).format(
oppiaid=oppiaid, src=self.src, width=self.width,
height=self.height))
js_str = pkg_resources.resource_string(
__name__, "static/js/oppia_edit.js")
frag.add_javascript(unicode(js_str))
frag.initialize_js('OppiaXBlockEditor')
return frag
@XBlock.json_handler
def studio_submit(self, data, suffix=''):
"""
Called when submitting the form in Studio.
"""
self.oppiaid = data.get('oppiaid')
self.src = data.get('src')
self.width = data.get('width')
self.height = data.get('height')
return {'result': 'success'}
@staticmethod
def workbench_scenarios():
"""A canned scenario for display in the workbench."""
return [
("Oppia Embedding",
"""<vertical_demo>
<oppia oppiaid="0" src="https://www.oppia.org" width="700" />
</vertical_demo>
"""),
]
This static directory is for files that should be included in your kit as plain
static files.
You can ask the runtime for a URL that will retrieve these files with:
url = self.runtime.local_resource_url(self, "static/js/lib.js")
The default implementation is very strict though, and will not serve files from
the static directory. It will serve files from a directory named "public".
Create a directory alongside this one named "public", and put files there.
Then you can get a url with code like this:
url = self.runtime.local_resource_url(self, "public/js/lib.js")
The sample code includes a function you can use to read the content of files
in the static directory, like this:
frag.add_javascript(self.resource_string("static/js/my_block.js"))
<div class="oppia_block">
<oppia oppia-id="{self.oppiaid}" src="{self.src}"
width="{self.width}" height="{self.height}"></oppia>
</div>
<div class="wrapper-comp-settings is-active editor-with-buttons" id="settings-tab">
<ul class="list-input settings-list">
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="oppiaid">Oppia exploration ID</label>
<input class="input setting-input" name="oppiaid" id="oppiaid" value="{oppiaid}" type="text" />
</div>
<span class="tip setting-help">Example: a4j3jdj21tvv</span>
</li>
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="src">Oppia server URL</label>
<input class="input setting-input" name="src" id="src" value="{src}" type="text" />
</div>
<span class="tip setting-help">Example: https://www.oppia.org</span>
</li>
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="width">Width</label>
<input class="input setting-input" name="width" id="width" value="{width}" type="text" />
</div>
<span class="tip setting-help">Width of the embedded exploration</span>
</li>
<li class="field comp-setting-entry is-set">
<div class="wrapper-comp-setting">
<label class="label setting-label" for="height">Height</label>
<input class="input setting-input" name="height" id="height" value="{height}" type="text" />
</div>
<span class="tip setting-help">Height of the embedded exploration</span>
</li>
</ul>
<div class="xblock-actions">
<ul>
<li class="action-item">
<a href="#" class="button action-primary save-button">Save</a>
</li>
<li class="action-item">
<a href="#" class="button cancel-button">Cancel</a>
</li>
</ul>
</div>
</div>
// Copyright 2015 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Javascript for Oppia XBlock.
*/
function OppiaXBlock(runtime, element) {
var onLoadHandlerUrl = runtime.handlerUrl(
element, 'on_exploration_loaded');
var onStateTransitionUrl = runtime.handlerUrl(
element, 'on_state_transition');
var onCompleteHandlerUrl = runtime.handlerUrl(
element, 'on_exploration_completed');
$(function ($) {
window.OPPIA_PLAYER.onExplorationLoadedPostHook = function(iframeNode) {
$.ajax({
type: "POST",
url: onLoadHandlerUrl,
data: JSON.stringify({})
});
};
window.OPPIA_PLAYER.onStateTransitionPostHook = function(
iframeNode, oldStateName, jsonAnswer, newStateName) {
$.ajax({
type: "POST",
url: onStateTransitionUrl,
data: JSON.stringify({
oldStateName: oldStateName,
jsonAnswer: jsonAnswer,
newStateName: newStateName
})
});
};
window.OPPIA_PLAYER.onExplorationCompletedPostHook = function(iframeNode) {
$.ajax({
type: "POST",
url: onCompleteHandlerUrl,
data: JSON.stringify({})
});
};
});
}
// Copyright 2015 The Oppia Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/**
* @fileoverview Javascript for Oppia XBlock editor.
*/
function OppiaXBlockEditor(runtime, element) {
$(element).find('.save-button').bind('click', function() {
var handlerUrl = runtime.handlerUrl(element, 'studio_submit');
var data = {
oppiaid: $(element).find('input[name=oppiaid]').val(),
src: $(element).find('input[name=src]').val(),
width: $(element).find('input[name=width]').val(),
height: $(element).find('input[name=height]').val()
};
runtime.notify('save', {state: 'start'});
$.post(handlerUrl, JSON.stringify(data)).done(function(response) {
runtime.notify('save', {state: 'end'});
});
});
$(element).find('.cancel-button').bind('click', function() {
runtime.notify('cancel', {});
});
}
# coding: utf-8
#
# Copyright 2015 The Oppia Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS-IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Setup for oppia XBlock."""
import os
from setuptools import setup
def package_data(pkg, roots):
"""Generic function to find package_data.
All of the files under each of the `roots` will be declared as package
data for package `pkg`.
"""
data = []
for root in roots:
for dirname, _, files in os.walk(os.path.join(pkg, root)):
for fname in files:
data.append(os.path.relpath(os.path.join(dirname, fname), pkg))
return {pkg: data}
setup(
name='oppia-xblock',
version='0.0.0',
description='An XBlock for embedding Oppia explorations',
packages=[
'oppia',
],
install_requires=[
'XBlock',
],
entry_points={
'xblock.v1': [
'oppia = oppia:OppiaXBlock',
]
},
package_data=package_data("oppia", ["static", "public"]),
)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment