-
Notifications
You must be signed in to change notification settings - Fork 218
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #672 from openedx/farhan/move-xblock-utils-docs
Move xblock-utils repository docs
- Loading branch information
Showing
5 changed files
with
337 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
.. _XBlock Utils: | ||
|
||
|
||
Xblock.utils | ||
############ | ||
|
||
Package having various utilities for XBlocks | ||
******************************************** | ||
|
||
|
||
Purpose | ||
======= | ||
|
||
``xblock/utils`` package contains a collection of utility functions and base test classes that are useful for any XBlock. | ||
|
||
|
||
Documentation | ||
============= | ||
|
||
|
||
StudioEditableXBlockMixin | ||
------------------------- | ||
|
||
.. code:: python | ||
from xblock.utils.studio_editable import StudioEditableXBlockMixin | ||
This mixin will automatically generate a working ``studio_view`` form | ||
that allows content authors to edit the fields of your XBlock. To use, | ||
simply add the class to your base class list, and add a new class field | ||
called ``editable_fields``, set to a tuple of the names of the fields | ||
you want your user to be able to edit. | ||
|
||
.. code:: python | ||
@XBlock.needs("i18n") | ||
class ExampleBlock(StudioEditableXBlockMixin, XBlock): | ||
... | ||
mode = String( | ||
display_name="Mode", | ||
help="Determines the behaviour of this component. Standard is recommended.", | ||
default='standard', | ||
scope=Scope.content, | ||
values=('standard', 'crazy') | ||
) | ||
editable_fields = ('mode', 'display_name') | ||
That's all you need to do. The mixin will read the optional | ||
``display_name``, ``help``, ``default``, and ``values`` settings from | ||
the fields you mention and build the editor form as well as an AJAX save | ||
handler. | ||
|
||
If you want to validate the data, you can override | ||
``validate_field_data(self, validation, data)`` and/or | ||
``clean_studio_edits(self, data)`` - see the source code for details. | ||
|
||
Supported field types: | ||
|
||
* Boolean: | ||
``field_name = Boolean(display_name="Field Name")`` | ||
* Float: | ||
``field_name = Float(display_name="Field Name")`` | ||
* Integer: | ||
``field_name = Integer(display_name="Field Name")`` | ||
* String: | ||
``field_name = String(display_name="Field Name")`` | ||
* String (multiline): | ||
``field_name = String(multiline_editor=True, resettable_editor=False)`` | ||
* String (html): | ||
``field_name = String(multiline_editor='html', resettable_editor=False)`` | ||
|
||
Any of the above will use a dropdown menu if they have a pre-defined | ||
list of possible values. | ||
|
||
* List of unordered unique values (i.e. sets) drawn from a small set of | ||
possible values: | ||
``field_name = List(list_style='set', list_values_provider=some_method)`` | ||
|
||
- The ``List`` declaration must include the property ``list_style='set'`` to | ||
indicate that the ``List`` field is being used with set semantics. | ||
- The ``List`` declaration must also define a ``list_values_provider`` method | ||
which will be called with the block as its only parameter and which must | ||
return a list of possible values. | ||
* Rudimentary support for Dict, ordered List, and any other JSONField-derived field types | ||
|
||
- ``list_field = List(display_name="Ordered List", default=[])`` | ||
- ``dict_field = Dict(display_name="Normal Dict", default={})`` | ||
|
||
Supported field options (all field types): | ||
|
||
* ``values`` can define a list of possible options, changing the UI element | ||
to a select box. Values can be set to any of the formats `defined in the | ||
XBlock source code <https://github.com/openedx/XBlock/blob/master/xblock/fields.py>`__: | ||
|
||
- A finite set of elements: ``[1, 2, 3]`` | ||
- A finite set of elements where the display names differ from the values:: | ||
|
||
[ | ||
{"display_name": "Always", "value": "always"}, | ||
{"display_name": "Past Due", "value": "past_due"}, | ||
] | ||
|
||
- A range for floating point numbers with specific increments: | ||
``{"min": 0 , "max": 10, "step": .1}`` | ||
- A callable that returns one of the above. (Note: the callable does | ||
*not* get passed the XBlock instance or runtime, so it cannot be a | ||
normal member function) | ||
* ``values_provider`` can define a callable that accepts the XBlock | ||
instance as an argument, and returns a list of possible values in one | ||
of the formats listed above. | ||
* ``resettable_editor`` - defaults to ``True``. Set ``False`` to hide the | ||
"Reset" button used to return a field to its default value by removing | ||
the field's value from the XBlock instance. | ||
|
||
Basic screenshot: |Screenshot 1| | ||
|
||
StudioContainerXBlockMixin | ||
-------------------------- | ||
|
||
.. code:: python | ||
from xblock.utils.studio_editable import StudioContainerXBlockMixin | ||
This mixin helps to create XBlocks that allow content authors to add, | ||
remove, or reorder child blocks. By removing any existing | ||
``author_view`` and adding this mixin, you'll get editable, | ||
re-orderable, and deletable child support in Studio. To enable authors to | ||
add arbitrary blocks as children, simply override ``author_edit_view`` | ||
and set ``can_add=True`` when calling ``render_children`` - see the | ||
source code. To restrict authors so they can add only specific types of | ||
child blocks or a limited number of children requires custom HTML. | ||
|
||
An example is the mentoring XBlock: |Screenshot 2| | ||
|
||
|
||
child\_isinstance | ||
------------------------- | ||
|
||
.. code:: python | ||
from xblock.utils.helpers import child_isinstance | ||
If your XBlock needs to find children/descendants of a particular | ||
class/mixin, you should use | ||
|
||
.. code:: python | ||
child_isinstance(self, child_usage_id, SomeXBlockClassOrMixin) | ||
rather than calling | ||
|
||
.. code:: python | ||
isinstance(self.runtime.get_block(child_usage_id), SomeXBlockClassOrMixin) | ||
On runtimes such as those in edx-platform, ``child_isinstance`` is | ||
orders of magnitude faster. | ||
|
||
.. |Screenshot 1| image:: Images/Screenshot_1.png | ||
.. |Screenshot 2| image:: Images/Screenshot_2.png | ||
|
||
XBlockWithSettingsMixin | ||
------------------------- | ||
|
||
This mixin provides access to instance-wide XBlock-specific configuration settings. | ||
See :ref:`accessing-xblock-specific-settings` for details. | ||
|
||
ThemableXBlockMixin | ||
------------------------- | ||
|
||
This mixin provides XBlock theming capabilities built on top of XBlock-specific settings. | ||
See :ref:`theming-support` for details. | ||
|
||
To learn more, refer to the page. | ||
|
||
.. toctree:: | ||
:caption: Contents: | ||
|
||
settings-and-theme-support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
.. _settings-and-theme-support: | ||
|
||
|
||
Settings and theme support | ||
########################## | ||
|
||
.. _accessing-xblock-specific-settings: | ||
|
||
Accessing XBlock specific settings | ||
********************************** | ||
|
||
XBlock utils provide a mixin to simplify accessing instance-wide | ||
XBlock-specific configuration settings: ``XBlockWithSettingsMixin``. | ||
This mixin aims to provide a common interface for pulling XBlock | ||
settings from the LMS | ||
`SettingsService <https://github.com/edx/edx-platform/blob/master/common/lib/xmodule/xmodule/services.py>`__. | ||
|
||
``SettingsService`` allows individual XBlocks to access environment and | ||
django settings in an isolated manner: | ||
|
||
- XBlock settings are represented as dictionary stored in `django | ||
settings <https://github.com/edx/edx-platform/blob/master/cms/envs/aws.py#L341-342>`__ | ||
and populated from environment \*.json files (cms.env.json and | ||
lms.env.json) | ||
- Each XBlock is associated with a particular key in that dictionary: | ||
by default an XBlock's class name is used, but XBlocks can override | ||
it using the ``block_settings_key`` attribute/property. | ||
|
||
Please note that at the time of writing the implementation of | ||
``SettingsService`` assumed "good citizenship" behavior on the part of | ||
XBlocks, i.e. it does not check for key collisions and allows modifying | ||
mutable settings. Both ``SettingsService`` and | ||
``XBlockWithSettingsMixin`` are not concerned with contents of settings | ||
bucket and return them as is. Refer to the ``SettingsService`` docstring | ||
and implementation for more details. | ||
|
||
Using XBlockWithSettingsMixin | ||
============================= | ||
|
||
In order to use ``SettingsService`` and ``XBlockWithSettingsMixin``, a | ||
client XBlock *must* require it via standard | ||
``XBlock.wants('settings')`` or ``XBlock.needs('settings')`` decorators. | ||
The mixins themselves are not decorated as this would not result in all | ||
descendant XBlocks to also be decorated. | ||
|
||
With ``XBlockWithSettingsMixin`` and ``wants`` decorator applied, | ||
obtaining XBlock settings is as simple as | ||
|
||
.. code:: python | ||
self.get_xblock_settings() # returns settings bucket or None | ||
self.get_xblock_settings(default=something) # returns settings bucket or "something" | ||
In case of missing or inaccessible XBlock settings (i.e. no settings | ||
service in runtime, no ``XBLOCK_SETTINGS`` in settings, or XBlock | ||
settings key is not found) ``default`` value is used. | ||
|
||
.. _theming-support: | ||
|
||
Theming support | ||
*************** | ||
|
||
XBlock theming support is built on top of XBlock-specific settings. | ||
XBlock utils provide ``ThemableXBlockMixin`` to streamline using XBlock | ||
themes. | ||
|
||
XBlock theme support is designed with two major design goals: | ||
|
||
- Allow for a different look and feel of an XBlock in different | ||
environments. | ||
- Use a pluggable approach to hosting themes, so that adding a new | ||
theme will not require forking an XBlock. | ||
|
||
The first goal made using ``SettingsService`` and | ||
``XBlockWithSettingsMixin`` an obvious choice to store and obtain theme | ||
configuration. The second goal dictated the configuration format - it is | ||
a dictionary (or dictionary-like object) with the following keys: | ||
|
||
- ``package`` - "top-level" selector specifying package which hosts | ||
theme files | ||
- ``locations`` - a list of locations within that package | ||
|
||
Examples: | ||
|
||
.. code:: python | ||
# will search for files red.css and small.css in my_xblock package | ||
{ | ||
'package': 'my_xblock', | ||
'locations': ['red.css', 'small.css'] | ||
} | ||
# will search for files public/themes/red.css in my_other_xblock.assets package | ||
default_theme_config = { | ||
'package': 'my_other_xblock.assets', | ||
'locations': ['public/themes/red.css'] | ||
} | ||
Theme files must be included into package (see `python | ||
docs <https://docs.python.org/2/distutils/setupscript.html#installing-package-data>`__ | ||
for details). At the time of writing it is not possible to fetch theme | ||
files from multiple packages. | ||
|
||
**Note:** XBlock themes are *not* LMS themes - they are just additional | ||
CSS files included into an XBlock fragment when the corresponding XBlock | ||
is rendered. However, it is possible to misuse this feature to change | ||
look and feel of the entire LMS, as contents of CSS files are not | ||
checked and might contain selectors that apply to elements outside of | ||
the XBlock in question. Hence, it is advised to scope all CSS rules | ||
belonging to a theme with a global CSS selector | ||
``.themed-xblock.<root xblock element class>``, e.g. | ||
``.themed-xblock.poll-block``. Note that the ``themed-xblock`` class is | ||
not automatically added by ``ThemableXBlockMixin``, so one needs to add | ||
it manually. | ||
|
||
Using ThemableXBlockMixin | ||
========================= | ||
|
||
In order to use ``ThemableXBlockMixin``, a descendant XBlock must also | ||
be a descendant of ``XBlockWithSettingsMixin`` (``XBlock.wants`` | ||
decorator requirement applies) or provide a similar interface for | ||
obtaining the XBlock settings bucket. | ||
|
||
There are three configuration parameters that govern | ||
``ThemableXBlockMixin`` behavior: | ||
|
||
- ``default_theme_config`` - default theme configuration in case no | ||
theme configuration can be obtained | ||
- ``theme_key`` - a key in XBlock settings bucket that stores theme | ||
configuration | ||
- ``block_settings_key`` - inherited from ``XBlockWithSettingsMixin`` | ||
if used in conjunction with it | ||
|
||
It is safe to omit ``default_theme_config`` or set it to ``None`` in | ||
case no default theme is available. In this case, | ||
``ThemableXBlockMixin`` will skip including theme files if no theme is | ||
specified via settings. | ||
|
||
``ThemableXBlockMixin`` exposes two methods: | ||
|
||
- ``get_theme()`` - this is used to get theme configuration. Default | ||
implementation uses ``get_xblock_settings`` and ``theme_key``, | ||
descendants are free to override it. Normally, it should not be | ||
called directly. | ||
- ``include_theme_files(fragment)`` - this method is an entry point to | ||
``ThemableXBlockMixin`` functionality. It calls ``get_theme`` to | ||
obtain theme configuration, fetches theme files and includes them | ||
into fragment. ``fragment`` must be an | ||
`XBlock.Fragment <https://github.com/edx/XBlock/blob/master/xblock/fragment.py>`__ | ||
instance. | ||
|
||
So, having met usage requirements and set up theme configuration | ||
parameters, including theme into XBlock fragment is a one liner: | ||
|
||
.. code:: python | ||
self.include_theme_files(fragment) |