Personal tools
You are here: Home Documentation How-Tos Using a KSS plugin for Drag-and-Drop

Using a KSS plugin for Drag-and-Drop

This How-to applies to: 1.0
This How-to is intended for: Developer

In addition to the core commands that kss.core provides, richer client actions can be plugged into the KSS machinery. In this example, we use a plugin called kss.plugin.yuidnd. This plugin provides drag-and-drop using the Yahoo UI library.

This howto extends the example described in Adding AJAX to Grok with KSS

Before you can use the KSS commands provided by the plugin a number of things have to be setup:

  • Define a dependency on the plugin in setup.py,
  • Rerun buildout.

Edit the Configuration file

Add your plugin to setup.py. We add kss.plugin.yuidnd:

...
install_requires=['setuptools',
                  'grok',
                  'megrok.kss',
                  'kss.plugin.yuidnd', # <---
                  ],
...

Now run buildout to make it include the extra package:

bin/buildout

Drag-and-Drop example

In the <head> section of index.pt, add the following list of <script> tags just above the @@kss_javascript:

<script src="++resource++yahoo.js" type="text/javascript"></script>
<script src="++resource++dom.js" type="text/javascript"></script>
<script src="++resource++event.js" type="text/javascript"></script>
<script src="++resource++animation.js" type="text/javascript"></script>
<script src="++resource++dragdrop.js" type="text/javascript"></script>

<tal:kss_javascript replace="structure context/@@kss_javascript" />
<link tal:attributes="href static/app.kss"
      rel="kinetic-stylesheet" type="text/kss" />

These scripts are the parts of the Yahoo library used by the plugin; without them, KSS will crash.

Next, add two lists of items to the bottom of index.pt:

<p>You can drag and drop items on the client.</p>

<ul id="first">
  <li id="f1">Item A</li>
  <li id="f2">Item B</li>
  <li id="f3">Item C</li>
  <li id="f4">Item D</li>
</ul>

<ul id="second">
  <li id="s1">Item 1</li>
  <li id="s2">Item 2</li>
  <li id="s3">Item 3</li>
  <li id="s4">Item 4</li>
</ul>

In the first how-to the app.kss file was added to the package (in src/ksssample). In there, add the following KSS rules.

li:yuidnd-dragstart {
   evt-yuidnd-dragstart-action: delete;
}

ul:yuidnd-drop  {
    evt-yuidnd-drop-action: order;
}

The first rule binds a dragstart event on all <li>'s. The second rule sets up a drop event on a container: All children of this container will be dynamically reordered when dropping an element.

After refreshing the page, start dragging elements from the first to the second list or even reorder elements within one list. This is all happening on the client side only at this moment, so it's not that useful.

To notify the server when something is successfully dragged, add the following KSS rule.

li:yuidnd-dragsuccess {
  action-server: drop url('@@index/@@drop');
  drop-container: pass(dropContainerId);
  drop-index: pass(dropIndex);
}

The dragsuccess event triggers an action-server which passes two arguments.

  • container - The HTML id of the container in which the element is dropped.
  • index - The place where the element is dropped in the container.

In the app.py, add a drop method to the AppKSS class defined there in order to process the dragsuccess event. The complete class should afterwards look like this (the welcome method is not necessary for this example):

from megrok.kss import KSS
...
class AppKSS(KSS):
  grok.view(Index)

  def welcome(self):
    core = self.getCommandSet('core')
    core.replaceHTML('#click-me', '<p>ME GROK KISSED !</p>')

  def drop(self, container, index):
    """This method gets called from kss and will display a message"""
    core = self.getCommandSet('core')
    core.replaceInnerHTML(
      '#message',
      '<p>You dropped something in %s at %s !</p>' % (container, index))

The final step is to add a placeholder <div> to the bottom of the index.pt so the drop method can replace it's contents:

<div id="message"></div>

Now restart Zope, because a new method has been added to the app.py. After refreshing the page, drag-and-drop an element and notice the message that is displayed.

Getting rid of ++resource++ links using hurry.yui

Instead of adding all the ++resource++ links in your page template manually, you can use hurry.yui to let that files be included more programmatically. To do this you must perform the following additional steps:

  1. Edit setup.py to require also hurry.yui and hurry.zoperesource:
...
install_requires=['setuptools',
                  'grok',
                  ...
                  'megrok.kss',
                  'kss.plugin.yuidnd',
                  'hurry.zoperesource', # <----
                  'hurry.yui',          # <----
                  ],
...

Rerun buildout afterwards:

$ ./bin/buildout

which will add these new eggs to your runtime environment. hurry.zoperesource is needed to register the resources (JavaScript files) provided by hurry.yui automatically with Zope on startup.

So, while hurry.yui brings in all the JavaScript files and their dependencies, hurry.zoperesource makes them known to the Zope publishing machinery.

  1. Edit app.py and change the Index view to look like this:
# app.py
from hurry import yui

...

class Index(grok.View):
  def update(self):
      yui.animation.need()
      yui.dragdrop.need()
This will take care, that upon request for the Index view the appropriate JavaScript files for YUI drag-and-drop functionality are included in the page header.
  1. Remove the <script> tags from index.pt header where ++resource++ files are included. Just leave in:
...
<head>
  <tal:kss_javascript replace="structure context/@@kss_javascript" />
  <link tal:attributes="href static/app.kss"
        rel="kinetic-stylesheet" type="text/kss" />
</head>
...

After performing these steps and starting your instance everything should work as before but you don't have to edit page templates for inclusion of cryptic JavaScript resources anymore. At least you don't have to know anymore under which resource path one can find a certain JavaScript path and hurry.yui will know about dependencies of JavaScript files automatically.