jeroen vloothuis bend kss to your will
DESCRIPTION
KSS, the new Ajax framework for Plone 3 comes with great components by default. But what if you need to integrate it with legacy Javascript? Or maybe you want to integrate that nice library/widget you found on the web. During this talk I will show you where you can extend KSS and how to do it. You can watch me create both the server side and client side code needed to integrate an existing piece of Javascript. After this talk KSS should have no limits for you.TRANSCRIPT
Bending KSS to your will
What KSS is about?
Making Ajax apps without writing Javascript
Subject of this talk
Extending KSS, both client and server side
Reasons for extending
● KSS might not be feature complete● You have existing Javascript code● Your project needs something special
Extending means
● Creating a plugin– Client side (Javascript)
● Actions● Value providers● Events
– Server side (Python)● Command sets
KSS terminologie
#selector:click {
action-client: do-stuff;
do-stuff: read-var(...);
}
event
action
value provider
Command setsfrom kss.core import kssaction, KSSView
class CanvasView(KSSView):
@kssaction def drawRectangle(self, size): ksscore = self.getCommandSet('core') selector = ksscore.getHtmlIdSelector( 'canvas-commandset')
self.getCommandSet('demoplugin').canvasRect( selector, 10, 10, size, size)
commandset
Get your gear
● Requirements– Plone 3
– Paster (PasteScript)
– kss.templates
kss.templates?
● kss_plugin● kss_zope_plugin
Using kss.templates
$ ./bin/paster create -t kss_zope_plugin
Selected and implied templates:
kss.templates#kss_plugin KSS plugin template
kss.templates#kss_zope_plugin KSS Zope plugin template
Enter project name: KSSDemoPlugin
Variables:
egg: KSSDemoPlugin
package: kssdemoplugin
project: KSSDemoPlugin
Enter namespace (The namespace for your plugin (something like `my-namespace`)) ['']: demoplugin
Creating template kss_plugin
...
Running /usr/bin/python2.4 setup.py egg_info
Look at all the goodies
● KSSDemoPlugin/– README.txt
– setup.py
– kssplugindemo/
● kssplugindemo/● README.txt● __init__.py● commands.py● configure.zcml● interfaces.py● javascript/plugin.js● etc.
Starting with Javascript
● javascript/plugin.js● 3 sections
– Action
– Value provider
– Event
Action
● Demo
Action (configure.zcml)
<!-- snip -->
<kss:action
name="demoplugin-canvasRect"
jsfile="javascript/plugin.js"
command_factory="selector"
params_mandatory="x y width height"
params_optional="fillStyle"
/>
Action (plugin.js)kukit.actionsGlobalRegistry.register('demoplugin-canvasRect', function (oper) {;;; oper.componentName = '[demoplugin-canvasRect] action'; oper.evaluateParameters(['x', 'y', 'width', 'height'], {'fillStyle': 'rgb(0, 255, 0)'}); oper.evalInt('x'); oper.evalInt('y'); oper.evalInt('width'); oper.evalInt('height');
var x = oper.parms.x; var y = oper.parms.y;
var ctx = oper.node.getContext("2d");
ctx.fillStyle = oper.parms.fillStyle; ctx.fillRect(x, y, oper.parms.width, oper.parms.height);});
kukit.commandsGlobalRegistry.registerFromAction( 'demoplugin-canvasRect', kukit.cr.makeSelectorCommand);
Action (plone-demo-plugin.kss)
#canvas:load {
action-client: demoplugin-canvasRect;
demoplugin-canvasRect-x: 10;
demoplugin-canvasRect-y: 10;
demoplugin-canvasRect-width: 200;
demoplugin-canvasRect-height: 200;
demoplugin-canvasRect-fillStyle: "rgb(0, 255, 0)";
}
Value provider
● Demo
Value provider (configure.zcml)
<!-- snip -->
<kss:paramprovider
name="demoplugin-random"
jsfile="javascript/plugin.js"
/>
Value provider (plugin.js)var RandomProvider = function() {};RandomProvider.prototype = {;;; check: function(args) {;;; if (args.length < 1) {;;; throw new Error( 'demoplugin-random needs at least 1 argument [max]');;;; };;; }, eval: function(args, node) { if(args.length == 2){ var min = args[0]; var max = args[1]; } else { var min = 0; var max = args[0]; } var range = max – min; var rand = (Math.random() * range) + min; return rand; }};kukit.pprovidersGlobalRegistry.register( 'demoplugin-random', RandomProvider);
Value provider (plone-demo-plugin.kss)#canvas:timeout {
evt-timeout-delay: 1;
evt-timeout-repeat: True;
action-client: demoplugin-canvasRect;
demoplugin-canvasRect-x: demoplugin-random(300);
demoplugin-canvasRect-y: demoplugin-random(300);
demoplugin-canvasRect-width: demoplugin-random(10, 30);
demoplugin-canvasRect-height: demoplugin-random(10, 30);
demoplugin-canvasRect-fillStyle: demoplugin-randomColor();
}
Event
● Demo
Event (configure.zcml)
<!-- snip -->
<kss:eventtype
name="demoplugin-movement"
jsfile="javascript/plugin.js"
/>
Event – part 1 (plone-demo-plugin.kss)
var MovementEventBinder = function() {
this.x = 0;
this.y = 0;
};
Event – part 2 (plugin.js)MovementEventBinder.prototype.__bind__ = function(name, func_to_bind, oper) {;;; oper.componentName = '[demoplugin-movement] event binding'; var keyMovement = { 37: [-1, 0], // left 38: [0, -1], // up 39: [1, 0], // right 40: [0, 1] // down };
oper.completeParms([], {'x': '0', 'y': '0', 'speed': '1'}, 'movement event binding'); oper.evalInt('x'); oper.evalInt('y'); oper.evalInt('speed');
var self = this; var speed = oper.parms.speed;
var f = oper.makeExecuteActionsHook();
func = function(e) { var keyCode = e.keyCode.toString(); if(typeof(keyMovement[keyCode]) == 'undefined'){ return; } self.x += keyMovement[keyCode][0] * speed; self.y += keyMovement[keyCode][1] * speed;
f({defaultParameters: {'x': self.x, 'y': self.y}}); }; kukit.ut.registerEventListener(document, 'keydown', func);};
kukit.eventsGlobalRegistry.register('demoplugin', 'movement', MovementEventBinder, '__bind__', null);
Event (plone-demo-plugin.kss)#canvas:demoplugin-movement {
action-client: demoplugin-canvasRect;
evt-demoplugin-movement-speed: 10;
demoplugin-canvasRect-x: pass(x);
demoplugin-canvasRect-y: pass(y);
demoplugin-canvasRect-width: 10;
demoplugin-canvasRect-height: 10;
demoplugin-canvasRect-fillStyle: "rgb(255, 0, 255)";
}
Commandset
● Demo
Commandset (configure.zcml)
<!-- snip -->
<kss:commandset
name="demoplugin"
for="kss.core.interfaces.IKSSView"
class=".commands.KSSDemoPluginCommands"
provides=".interfaces.IKSSDemoPluginCommands"
/>
Commandset (commands.py)
from kss.core.kssview import CommandSet
class KSSDemoPluginCommands(CommandSet):
def canvasRect(self, selector, x, y, width, height, fillStyle=None): command = self.commands.addCommand( 'demoplugin-canvasRect', selector) command.addParam('x', str(int(x))) command.addParam('y', str(int(y))) command.addParam('width', str(int(width))) command.addParam('height', str(int(height)))
if fillStyle is not None: command.addParam('fillStyle', fillStyle)
Commandset (plone-demo-plugin.kss)#canvas-commandset:load {
action-server: drawRectangle;
drawRectangle-size: 200;
}
Using the commandset (plonedemo/canvas.py)
from kss.core import kssaction, KSSView
class CanvasView(KSSView): @kssaction def drawRectangle(self, size): ksscore = self.getCommandSet('core') selector = ksscore.getHtmlIdSelector( 'canvas-commandset')
self.getCommandSet('demoplugin').canvasRect( selector, 10, 10, size, size)
Wrap up
● Creating plugins not that hard● More docs on: http://kssproject.org● Remember:
– KSS is about not having to write Javascript!