Skip to content

Commit

Permalink
[#847] Add draft of first JavaScript tutorial
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Hammond committed Nov 20, 2013
1 parent 542a72d commit 983bb02
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 17 deletions.
Empty file.
@@ -0,0 +1,8 @@
ckan.module('favorite', function (jQuery, _) {
return {
initialize: function () {
console.log("I've been initialized for element: %o", this.el);
}
};
});

14 changes: 14 additions & 0 deletions ckanext/example_theme/v14_initialize_a_javascript_module/plugin.py
@@ -0,0 +1,14 @@
import ckan.plugins as plugins
import ckan.plugins.toolkit as toolkit


class ExampleThemePlugin(plugins.SingletonPlugin):
'''An example theme plugin.
'''
plugins.implements(plugins.IConfigurer)

def update_config(self, config):

toolkit.add_template_directory(config, 'templates')
toolkit.add_resource('fanstatic', 'example_theme')
@@ -0,0 +1,15 @@
{% ckan_extends %}


{% block content %}

{{ super() }}

{# Use Fanstatic to include our custom JavaScript module. #}
{% resource 'example_theme/favorite.js' %}

<form action="/favorite" method="post" data-module="favorite">
<button class="btn" name="package" value="101">Submit</button>
</form>

{% endblock %}
@@ -0,0 +1,22 @@
{% ckan_extends %}

{% block package_item_content %}
{{ super() }}

{# Use Fanstatic to include our custom JavaScript module.
A <script> tag for the module will be inserted in the right place at the
bottom of the page.
#}
{% resource 'example_theme/favorite.js' %}

{# Apply our JavaScript module to an HTML element. The data-module attribute,
which can be applied to any HTML element, tells CKAN to initialize an
instance of the named JavaScript module for the element.
The initialize() method of our module will be called with this HTML
element as its this.el object.
#}
<form action="/api/3/action/dataset_favorite" method="post"
data-module="favorite">
<button class="btn" href="#"><i class="icon-star"></i></button>
</form>
{% endblock %}
133 changes: 116 additions & 17 deletions doc/theming.rst
Expand Up @@ -840,19 +840,6 @@ implements a partial imitation of the `datahub.io <http://datahub.io/>`_ theme
We use LESS for the CKAN core CSS. Do we want to mention that here?


-----------------------------
Customizing CKAN's JavaScript
-----------------------------

.. Use the scripts block in base.html to add a global javascript file
.. todo::

* How to load JavaScript modules
* jQuery
* Bootstrap's JavaScript stuff
* Other stuff in javascript-module-tutorial.rst

.. _fanstatic tutorial:

------------------------------------------------
Expand All @@ -861,12 +848,13 @@ Adding |javascript| and CSS file using Fanstatic

If you're adding |javascript| or CSS files to your theme, you can add them
using `Fanstatic <http://www.fanstatic.org/>`_ rather than the simple
:ref:`extra_public_paths` method described above. Using Fanstatic to add
:ref:`extra_public_paths` method described above (`JavaScript modules
<javascript modules>`_ *must* be added using Fanstatic). Using Fanstatic to add
|javascript| and CSS files allows you to take advantage of Fanstatic's
features, such as automatically serving minified files in production, caching
and bundling files together to reduce page load times, specifying
dependencies between files so that the files a page needs (and only the files
it needs) are always loaded, and other tricks to optimize page load times.
and bundling files together to reduce page load times, specifying dependencies
between files so that the files a page needs (and only the files it needs) are
always loaded, and other tricks to optimize page load times.

.. note::

Expand Down Expand Up @@ -925,3 +913,114 @@ Fanstatic resource troubleshooting

``AttributeError``
------------------

.. _javascript modules:

-----------------------------
Customizing CKAN's JavaScript
-----------------------------

.. todo:: Link to an introductory JavaScript tutorial.

.. todo:: Introduce the example we're doing here: starring datasets using a
custom dataset_star action (also need the code to add this action).

.. todo:: Explain that Bootstrap's JavaScript features can be used just by CSS.


Initializing a JavaScript module
================================

To get CKAN to call some custom JavaScript code, we need to:

1. Implement a |javascript| module, and register it with CKAN.
Create the file ``ckanext-example_theme/fanstatic/favorite.js``, with these
contents:

.. literalinclude:: ../ckanext/example_theme/v14_initialize_a_javascript_module/fanstatic/favorite.js

This bit of |javascript| calls the ``ckan.module()`` function to register a
new JavaScript module with CKAN. ``ckan.module()`` takes two arguments: the
name of the module being registered (``'favorite'`` in this example) and a
function that returns the module itself. The function takes two arguments,
which we'll look at later. The module is just a |javascript| object with a
single attribute, ``initialize``, whose value is a function that CKAN will
call to initialize the module. In this example, the initialize function just
prints out a confirmation message - this |javascript| module doesn't do
anything interesting yet.

2. Include the |javascript| module in a page, using Fanstatic, and apply it to
one or more HTML elements on that page. We'll override CKAN's
``package_item.html`` template snippet to insert our module whenever a
package is rendered as part of a list of packages (for example, on the
dataset search page). Create the file
``ckanext-example_theme/templates/snippets/package_item.html`` with these
contents:

.. literalinclude:: ../ckanext/example_theme/v14_initialize_a_javascript_module/templates/snippets/package_item.html

.. todo:: Link to something about HTML data-* attributes.

If you now restart the development server and open
http://127.0.0.1:5000/dataset in your web browser, you should see an
extra "star this dataset" button next to each dataset shown. If you open a
|javascript| console in your browser, you should see the message that your
module has printed out.

.. todo:: Link to something about JavaScript consoles.

If you have more than one dataset on your page, you'll see the module's
message printed once for each dataset. The ``package_item.html`` template
snippet is rendered once for each dataset that's shown in the list, and
CKAN creates a new instance of your |javascript| module for each dataset.
If you view the source of your page, however, you'll see that
``favorite.js`` is only included with a ``<script>`` tag once. Fanstatic
is smart enough to deduplicate resources.

.. note:: |javascript| modules *must* be included as Fanstatic resources,
you can't add them to a ``public`` directory and include them using your
own ``<script>`` tags.

.. Link to some JavaScript tutorial?
JavaScript modules are the core - every javascripted object should be a
module. Small, isolated components that can be easily tested. They should
not use any global objects, all functionality provided to them via a sandbox
object.
A module is a JavaScript object with an initialize() and a teardown()
method.
Initialize a module with a data-module attribute:
<select name="format" data-module="autocomplete"></select>
Or apparently you can also use {% resource %}? Or you have to use resource?
"favorite" module goes in favorite.js file.
The idea is that the HTML element should still work fine is JavaScript is
disabled - e.g. use form submission instead of XHR request.
You can pass "options objects" with further data-module-* attributes.
The modules are initialized "on DOM ready", each module's initialize()
method is called.
this.sandbox.jQuery - access jQuery methods
this.sandbox.translte() - i18n
(or these are the jQuery and _ params of your module function)
pub/sub for sending messages between modules:
this.sandbox.publish/subscribe/unsubscribe
this.sandbox.client should be used to make XHR requests to the CKAN API
(not jQuery.ajax())
i18n: this.sandbox.translate(), supports %(name)s, including plurals.
The options() method of each module should set all strings to be i18n'd?
Then other code uses this.18n() to retrieve them.
If not CKAN specific, module functionality should be packaged up in jQuery
plugins.
Testing.
1 change: 1 addition & 0 deletions setup.py
Expand Up @@ -92,6 +92,7 @@
'example_theme_v11 = ckanext.example_theme.v11_extra_public_directory.plugin:ExampleThemePlugin',
'example_theme_v12 = ckanext.example_theme.v12_custom_css.plugin:ExampleThemePlugin',
'example_theme_v13 = ckanext.example_theme.v13_more_custom_css.plugin:ExampleThemePlugin',
'example_theme_v14 = ckanext.example_theme.v14_initialize_a_javascript_module.plugin:ExampleThemePlugin',
],
'ckan.system_plugins': [
'domain_object_mods = ckan.model.modification:DomainObjectModificationExtension',
Expand Down

0 comments on commit 983bb02

Please sign in to comment.