This section describes how to modify the Python file of the XBlock you created,
myxblock.py
, to provide the functionality in the Thumbs XBlock example in
the XBlock SDK.
In myxblock.py
, you will define fields,
views, handlers, and workbench
scenarios.
When you create a new XBlock, the default
Python file is created automatically, with skeletal functionality defined. In
the xblock_development/myxblock/myxblock/
directory, see the file
myxblock.py
.
"""TO-DO: Write a description of what this XBlock is."""
import pkg_resources
from xblock.core import XBlock
from xblock.fields import Scope, Integer
from xblock.fragment import Fragment
class MyXBlock(XBlock):
"""
TO-DO: document what your XBlock does.
"""
# Fields are defined on the class. You can access them in your code as
# self.<fieldname>.
# TO-DO: delete count, and define your own fields.
count = Integer(
default=0, scope=Scope.user_state,
help="A simple counter, to show something happening",
)
def resource_string(self, path):
"""Handy helper for getting resources from our kit."""
data = pkg_resources.resource_string(__name__, path)
return data.decode("utf8")
# TO-DO: change this view to display your data your own way.
def student_view(self, context=None):
"""
The primary view of the MyXBlock, shown to students
when viewing courses.
"""
html = self.resource_string("static/html/myxblock.html")
frag = Fragment(html.format(self=self))
frag.add_css(self.resource_string("static/css/myxblock.css"))
frag.add_javascript(self.resource_string("static/js/src/myxblock.js"))
frag.initialize_js('MyXBlock')
return frag
# TO-DO: change this handler to perform your own actions. You may need more
# than one handler, or you may not need any handlers at all.
@XBlock.json_handler
def increment_count(self, data, suffix=''):
"""
An example handler, which increments the data.
"""
# Just to show data coming in...
assert data['hello'] == 'world'
self.count += 1
return {"count": self.count}
# TO-DO: change this to create the scenarios you'd like to see in the
# workbench while developing your XBlock.
@staticmethod
def workbench_scenarios():
"""A canned scenario for display in the workbench."""
return [
("MyXBlock",
"""<vertical_demo>
<myxblock/>
<myxblock/>
<myxblock/>
</vertical_demo>
"""),
]
As a best practice and because XBlocks can be shared, you should add comments
to the myxblock.py
file. Replace the “TO DO” indicators with a description
of what the XBlock does and any details future developers or users would want
to know.
You determine the data your XBlock stores through fields. Fields store user and XBlock state as JSON data.
To customize your myxblock.py
file so that it has the same functionality
as the thumbs.py
file, you need to add three fields to the XBlock, each
with the right scope.
upvotes
, to store the number of times users up-vote the XBlock. The value
applies to the XBlock and all users collectively.downvotes
, to store the number of times users down-vote the XBlock. The
value applies to the XBlock and all users collectively.voted
, to record whether or not the user has voted. The value applies to
the XBlock and each user individually.Review the XBlock Fields section, then add the required fields to
myxblock.py
. You can remove the count
field, which was defined
automatically when you created the XBlock.
After you have defined the fields, check your work against the fields in the
Thumbs XBlock, in the file xblock_development/xblock-sdk/sample_xblocks/thumbs/thumbs.py
.
class ThumbsBlockBase(object):
upvotes = Integer(help="Number of up votes", default=0,
scope=Scope.user_state_summary)
downvotes = Integer(help="Number of down votes", default=0,
scope=Scope.user_state_summary)
voted = Boolean(help="Has this student voted?", default=False,
scope=Scope.user_state)
If necessary, make corrections to the fields in your XBlock so that they match the fields in the Thumbs XBlock.
Note the following details.
upvotes
and downvotes
have the scope Scope.user_state_summary
.
This indicates that the data in these fields are specific to the XBlock and
the same for all users.voted
has the scope Scope.user_state
. This indicates that the data in
this field applies to the XBlock and to the specific user.The XBlock Python file must contain one or more view methods.
To run the XBlock in the edX Platform Learning Management System, there must be
a method named student_view
. If you intend the XBlock to run in a different
runtime application, you might need to define a
different name. For more information, see EdX Learning Management System as an XBlock Runtime.
In myxblock.py
, examine the student_view
method that was defined
automatically when you created the XBlock.
The student view composes and returns the fragment from static HTML, JavaScript, and CSS files. A web page displays the fragment to learners.
Note the following details about student view.
The static HTML is added when the fragment is initialized.
html = self.resource_string("static/html/myxblock.html")
frag = Fragment(unicode(html_str).format(self=self))
The JavaScript and CSS files are added to the fragment with the
add_javascript()
and add_css
methods.
The JavaScript in the fragment must be initialized using the name of the XBlock class. The name also maps to the function that initializes the XBlock in the JavaScript file.
frag.initialize_js('MyXBlock')
As you can see, the necessary functions of the view were added automatically.
Check the student view in myxblock.py
against the student view in
thumbs.py. Note that the only differences are the file names of the HTML,
CSS, and JavaScript files added to the fragment. As the file names are correct
for MyXBlock, you do not need to edit the student view at all.
Handlers process input events from the XBlock JavaScript code. You use handlers to add interactivity to your block. In your XBlock, you use a handler to process votes from users.
The vote handler in your XBlock must perform the following functions.
upvotes
or downvotes
fields based on the user’s vote.voted
field to True
for the user.upvotes
and downvotes
fields.Review the XBlock Methods section, then implement the vote handler
in myxblock.py
.
You can use any name for the vote handler, and you will use the same name in
the JavaScript code to connect browser events to the vote handler running in
the server. To match the Thumbs XBlock, use the name vote
.
After you have defined the vote handler, check your work against the handler in the Thumbs XBlock.
@XBlock.json_handler
def vote(self, data, suffix=''): # pylint: disable=unused-argument
"""
Update the vote count in response to a user action.
"""
# Here is where we would prevent a student from voting twice, but then
# we couldn't click more than once in the demo!
#
# if self.voted:
# log.error("cheater!")
# return
if data['voteType'] not in ('up', 'down'):
log.error('error!')
return
if data['voteType'] == 'up':
self.upvotes += 1
else:
self.downvotes += 1
self.voted = True
return {'up': self.upvotes, 'down': self.downvotes}
If necessary, make corrections to the handler in your XBlock so that it matches the handler in the Thumbs XBlock.
After you complete your customizations to the Python file, you continue on and customize the XBlock HTML file.