First commit
commit
2909a53756
|
@ -0,0 +1,8 @@
|
|||
*.class
|
||||
*.pyc
|
||||
*.pyo
|
||||
.svn
|
||||
__pycache__
|
||||
_svn
|
||||
/.project
|
||||
/.pydevproject
|
|
@ -0,0 +1,18 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>orun</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.python.pydev.PyDevBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>com.aptana.projects.webnature</nature>
|
||||
<nature>org.python.pydev.pythonNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<?eclipse-pydev version="1.0"?>
|
||||
|
||||
<pydev_project>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_INTERPRETER">Default</pydev_property>
|
||||
<pydev_property name="org.python.pydev.PYTHON_PROJECT_VERSION">python 2.7</pydev_property>
|
||||
</pydev_project>
|
|
@ -0,0 +1,43 @@
|
|||
====
|
||||
Orun
|
||||
====
|
||||
|
||||
Orun (Object RUNtime) is a small/lightweight library that provides a fast
|
||||
and full way to build Python RIA, the client communicates with the server
|
||||
through ajax. Typical usage often looks like this::
|
||||
|
||||
#!/usr/bin/env python
|
||||
# Cherrypy + ExtJS example
|
||||
|
||||
from orun.extjs import *
|
||||
from orun.extjs import cp
|
||||
|
||||
def ok_click(id, *args, **kwargs):
|
||||
cli << Ext.getCmp(id).setText('Clicked')
|
||||
cli << js.client.alert('Server side message')
|
||||
|
||||
def button_click(id, *args, **kwargs):
|
||||
js.write("""
|
||||
Ext.getCmp("%s").setText('Clicked');
|
||||
alert('Server side callback message');
|
||||
""" % id)
|
||||
|
||||
class MyApplication(cp.ExtApplication):
|
||||
def main(self, *args, **kwargs):
|
||||
wnd = Ext.create('widget.window', {'title': 'My Window', 'width': 300, 'height': 250,
|
||||
'items': [{'xtype': 'button', 'text': 'Click Here', 'handler': button_click}],
|
||||
'buttons': [
|
||||
{'text': 'OK', 'handler': ok_click},
|
||||
{'text': 'Close', 'handler': js.function('this.up("window").close();')}]})
|
||||
wnd.show()
|
||||
wnd.setHeight(200)
|
||||
|
||||
app = MyApplication('Orun (ExtJS Application)')
|
||||
app.run()
|
||||
|
||||
The example above, runs cherrypy application on 8080 http port, and exposes
|
||||
extjs method.
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
from orun import js
|
||||
|
||||
class Application(object):
|
||||
AJAX_URL = '/ajax_callback'
|
||||
|
||||
def __init__(self, title=''):
|
||||
self.title = title
|
||||
|
||||
def main(self):
|
||||
pass
|
||||
|
||||
def run(self):
|
||||
js.AJAX_URL = self.AJAX_URL
|
|
@ -0,0 +1,26 @@
|
|||
|
||||
from orun.extjs import *
|
||||
from orun.extjs import cp
|
||||
|
||||
def ok_click(id, *args, **kwargs):
|
||||
cli << Ext.getCmp(id).setText('Clicked')
|
||||
cli << js.client.alert('Server side message')
|
||||
|
||||
def button_click(id, *args, **kwargs):
|
||||
js.write("""
|
||||
Ext.getCmp("%s").setText('Clicked');
|
||||
alert('Server side callback message');
|
||||
""" % id)
|
||||
|
||||
class MyApplication(cp.ExtApplication):
|
||||
def main(self, *args, **kwargs):
|
||||
wnd = Ext.create('widget.window', {'title': 'My Window', 'width': 300, 'height': 250,
|
||||
'items': [{'xtype': 'button', 'text': 'Click Here', 'handler': button_click}],
|
||||
'buttons': [
|
||||
{'text': 'OK', 'handler': ok_click},
|
||||
{'text': 'Close', 'handler': js.function('this.up("window").close();')}]})
|
||||
wnd.show()
|
||||
wnd.setHeight(200)
|
||||
|
||||
app = MyApplication('Orun (ExtJS Application)')
|
||||
app.run()
|
|
@ -0,0 +1,5 @@
|
|||
|
||||
from orun import js
|
||||
from orun.js import client
|
||||
from . import base as Ext
|
||||
from .base import *
|
|
@ -0,0 +1,14 @@
|
|||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||||
<title>%s</title>
|
||||
<script src="http://cdn.sencha.com/ext/gpl/4.2.0/ext-all.js"></script>
|
||||
<link rel="stylesheet" href="http://cdn.sencha.com/ext/gpl/4.2.0/resources/ext-theme-classic/ext-theme-classic-all.css">
|
||||
<script>
|
||||
Ext.onReady(function () {
|
||||
%s
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
|
@ -0,0 +1,56 @@
|
|||
|
||||
import json
|
||||
from . import js
|
||||
|
||||
__all__ = ['create', 'createByAlias', 'Component']
|
||||
|
||||
def js_ajax(fn):
|
||||
i = id(fn)
|
||||
js.live_methods[i] = fn
|
||||
return js.client.Ext.Ajax.request({'url': js.AJAX_URL, 'method': 'GET', 'params': {'fn': i, 'id': js.client.this.id}, 'success': js.function('eval(arguments[0].responseText);')})
|
||||
|
||||
js.js_ajax = js_ajax
|
||||
|
||||
def _create(meth, name, args):
|
||||
#args['pyLive'] = True : TODO
|
||||
obj = Component(**args)
|
||||
js.write('var %s = Ext.create("%s", %s);' % (obj._id, name, str(obj)))
|
||||
return obj
|
||||
|
||||
def create(name, args={}):
|
||||
return _create('create', name, args)
|
||||
|
||||
def createByAlias(alias, args={}):
|
||||
return _create('createByAlias', alias, args)
|
||||
|
||||
def get(id):
|
||||
return js.JsNode('Ext.get("%s")' % id)
|
||||
|
||||
def getCmp(id):
|
||||
return js.JsNode('Ext.getCmp("%s")' % id)
|
||||
|
||||
class Component(js.JsObject):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(Component, self).__init__(*args, **kwargs)
|
||||
|
||||
def _update(self, config):
|
||||
def get_obj(value):
|
||||
if isinstance(value, dict):
|
||||
return Component(**v)
|
||||
elif isinstance(value, (list, tuple)):
|
||||
return [get_obj(v) for v in value]
|
||||
else:
|
||||
return value
|
||||
cfg = {}
|
||||
for k, v in config.items():
|
||||
cfg[k] = get_obj(v)
|
||||
super(Component, self).update(cfg)
|
||||
|
||||
def down(self, item):
|
||||
pass
|
||||
|
||||
def up(self, item):
|
||||
pass
|
||||
|
||||
def __str__(self):
|
||||
return json.dumps(self._js, default=js._encoder)
|
|
@ -0,0 +1,23 @@
|
|||
|
||||
import os
|
||||
from orun.extjs import *
|
||||
from orun.servers import cp
|
||||
|
||||
class ExtApplication(cp.Application):
|
||||
def index(self, *args, **kwargs):
|
||||
f = open(os.path.join(os.path.dirname(__file__), 'app.html')).read()
|
||||
self.main()
|
||||
return f % (self.title, str(js.js_manager))
|
||||
index.exposed = True
|
||||
|
||||
def ajax_callback(self, *args, **kwargs):
|
||||
fn = kwargs.pop('fn')
|
||||
if fn:
|
||||
fn = js.live_methods[int(fn)]
|
||||
fn(*args, **kwargs)
|
||||
return str(js.js_manager)
|
||||
ajax_callback.exposed = True
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = ExtApplication('Orun (ExtJS Application)')
|
||||
app.run()
|
|
@ -0,0 +1,187 @@
|
|||
|
||||
import types
|
||||
import json
|
||||
|
||||
AJAX_URL = '/ajax_callback'
|
||||
js_manager = None
|
||||
js_ajax = None
|
||||
|
||||
live_methods = {}
|
||||
|
||||
def _encoder(o):
|
||||
if isinstance(o, JsObject):
|
||||
return o._js
|
||||
elif isinstance(o, JsNode):
|
||||
return block(str(o))
|
||||
elif isinstance(o, types.FunctionType) and js_ajax:
|
||||
return function(js_ajax(o))
|
||||
|
||||
def encode(o):
|
||||
if isinstance(o, JsNode):
|
||||
return str(o)
|
||||
elif isinstance(o, (list, tuple)):
|
||||
return '[%s]' % ','.join([encode(i) for i in o])
|
||||
else:
|
||||
return json.dumps(o, default=_encoder)
|
||||
|
||||
# trick json serialize javascript block
|
||||
class JsBlock(int):
|
||||
def __new__(cls, *args, **kwargs):
|
||||
obj = super(JsBlock, cls).__new__(cls, 0)
|
||||
obj.code = args[0]
|
||||
return obj
|
||||
|
||||
def __str__(cls):
|
||||
return cls.code
|
||||
|
||||
class JsFunction(JsBlock):
|
||||
def __str__(cls):
|
||||
return 'function () { %s }' % cls.code
|
||||
|
||||
block = JsBlock
|
||||
func = function = JsFunction
|
||||
|
||||
def write(code):
|
||||
if js_manager:
|
||||
js_manager.write(str(code))
|
||||
|
||||
def __lshift__(self, value):
|
||||
print('test')
|
||||
|
||||
class JsManager(object):
|
||||
def __init__(self):
|
||||
self.output = []
|
||||
|
||||
def write(self, data):
|
||||
self.output.append(data)
|
||||
|
||||
def __str__(self):
|
||||
s = '\n'.join(output)
|
||||
output = self.output[:]
|
||||
return s
|
||||
|
||||
class JsNode(object):
|
||||
def __init__(self, name='', parent=None):
|
||||
if parent and parent.name:
|
||||
self.name = parent.name + '.' + name
|
||||
else:
|
||||
self.name = name
|
||||
|
||||
def __getattr__(self, attr):
|
||||
return JsNode(attr, self)
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if attr == 'name':
|
||||
super(JsNode, self).__setattr__(attr, value)
|
||||
else:
|
||||
value = encode(value)
|
||||
if self is client.var:
|
||||
s = 'var %s = %s' % (attr, value)
|
||||
else:
|
||||
name = self.name + '.' if self.name else ''
|
||||
s = '%s%s = %s' % (name, attr, value)
|
||||
write(s)
|
||||
|
||||
def __add__(self, other):
|
||||
return JsNode('%s + %s' % (encode(self), encode(other)))
|
||||
|
||||
def __sub__(self, other):
|
||||
return JsNode('%s - %s' % (encode(self), encode(other)))
|
||||
|
||||
def __mul__(self, other):
|
||||
return JsNode('%s * %s' % (encode(self), encode(other)))
|
||||
|
||||
def __truediv__(self, other):
|
||||
return JsNode('%s / %s' % (encode(self), encode(other)))
|
||||
|
||||
def __call__(self, *args, **kwargs):
|
||||
l = []
|
||||
d = []
|
||||
for arg in args:
|
||||
l.append(encode(arg))
|
||||
for k, v in kwargs.items():
|
||||
d.append('%s=%s' % (k, encode(v)))
|
||||
_args = []
|
||||
if l:
|
||||
_args.extend(l)
|
||||
if d:
|
||||
_args.extend(d)
|
||||
s = '%s(%s)' % (self.name, ','.join(_args))
|
||||
self.name = s
|
||||
return self
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class JsClient(JsNode):
|
||||
def __init__(self, name='', parent=None):
|
||||
if parent and parent.name:
|
||||
self.name = parent.name + '.' + name
|
||||
else:
|
||||
self.name = name
|
||||
self.__dict__['var'] = JsNode('var')
|
||||
|
||||
def __lshift__(self, other):
|
||||
write(other)
|
||||
|
||||
class JsObjectNode(JsNode):
|
||||
def __call__(self, *args, **kwargs):
|
||||
super(JsObjectNode, self).__call__(*args, **kwargs)
|
||||
write(str(self))
|
||||
|
||||
class JsObject(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self._loading = True
|
||||
self._id = 'js_%s' % id(self)
|
||||
self._create()
|
||||
self._js = kwargs
|
||||
self._loading = False
|
||||
|
||||
def _create(self):
|
||||
pass
|
||||
|
||||
def _update(self, config):
|
||||
self._js.update(config)
|
||||
|
||||
def __getattr__(self, attr):
|
||||
if not self.__dict__.get('_loading', True):
|
||||
if attr in self._js:
|
||||
return self._js.get(attr)
|
||||
else:
|
||||
return JsObjectNode(attr, JsNode(self._id))
|
||||
|
||||
def __setattr__(self, attr, value):
|
||||
if '_js' in self.__dict__ and not attr in self.__dict__:
|
||||
self[attr] = value
|
||||
else:
|
||||
super(JsObject, self).__setattr__(attr, value)
|
||||
|
||||
def __setitem__(self, attr, value):
|
||||
if not self._loading:
|
||||
write('%s.%s = %s' % (self._id, attr, json.dumps(value)))
|
||||
self._js[attr] = value
|
||||
|
||||
def load(filename, klass=JsObject):
|
||||
return klass(**json.load(open(filename)))
|
||||
|
||||
cli = client = JsClient()
|
||||
|
||||
def call(self, *args):
|
||||
print('call')
|
||||
|
||||
if __name__ == '__main__':
|
||||
class MyManager(JsManager):
|
||||
def write(self, code):
|
||||
print(code)
|
||||
js_manager = MyManager()
|
||||
write(client.console.log('test'))
|
||||
n = JsNode('console')
|
||||
write(n.print(n.log({'id': 'item id'})))
|
||||
client.var.x = 1
|
||||
client.x.y = client.window.open('http://www.google.com')
|
||||
client << client.x.y()([client.x])
|
||||
client << client.Ext.create('window', {'left': 10})
|
||||
client << client.x
|
||||
|
||||
# test block
|
||||
print(json.dumps({'click': call}, default=_encoder))
|
|
@ -0,0 +1,27 @@
|
|||
|
||||
import cherrypy
|
||||
from orun import js
|
||||
from orun import app
|
||||
|
||||
class Application(app.Application):
|
||||
def index(self):
|
||||
return 'Orun application server is running'
|
||||
index.exposed = True
|
||||
|
||||
def run(self, port=8080, config=None):
|
||||
super(Application, self).run()
|
||||
cherrypy.quickstart(self, '/', config)
|
||||
|
||||
class JsManager(object):
|
||||
def write(self, data):
|
||||
cherrypy.response.body.append(data)
|
||||
|
||||
def __str__(self):
|
||||
return ';\n'.join(cherrypy.response.body) + ';'
|
||||
|
||||
# Auto start cherrypy javascript manager
|
||||
js.js_manager = JsManager()
|
||||
|
||||
if __name__ == '__main__':
|
||||
app = Application()
|
||||
app.run()
|
|
@ -0,0 +1,7 @@
|
|||
|
||||
class Session(dict):
|
||||
def add_object(self, obj):
|
||||
self['js_' + id(obj)] = obj
|
||||
|
||||
def create_session():
|
||||
return Session()
|
|
@ -0,0 +1,13 @@
|
|||
from distutils.core import setup
|
||||
|
||||
setup(
|
||||
name='Orun',
|
||||
version='0.1.0',
|
||||
author='Alexandre L. Dias',
|
||||
author_email='alexandre@katrid.com',
|
||||
packages=['orun', 'orun.test'],
|
||||
url='http://pypi.python.org/pypi/Orun/',
|
||||
license='LICENSE.txt',
|
||||
description='Orun (Object RUNtime) Python JavaScript RIA framework.',
|
||||
long_description=open('README.txt').read(),
|
||||
)
|
Loading…
Reference in New Issue