commit 2909a5375629f1ac1985e4346b586d4f60893955 Author: unknown Date: Tue Apr 30 02:49:34 2013 -0300 First commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6eaad0c --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +*.class +*.pyc +*.pyo +.svn +__pycache__ +_svn +/.project +/.pydevproject diff --git a/.project b/.project new file mode 100644 index 0000000..81dcad3 --- /dev/null +++ b/.project @@ -0,0 +1,18 @@ + + + orun + + + + + + org.python.pydev.PyDevBuilder + + + + + + com.aptana.projects.webnature + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..a9cca03 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,7 @@ + + + + +Default +python 2.7 + diff --git a/CHANGES.txt b/CHANGES.txt new file mode 100644 index 0000000..e69de29 diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..e69de29 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..e69de29 diff --git a/README.txt b/README.txt new file mode 100644 index 0000000..1f377a7 --- /dev/null +++ b/README.txt @@ -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 +------------ + diff --git a/orun/__init__.py b/orun/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orun/app.py b/orun/app.py new file mode 100644 index 0000000..d82238a --- /dev/null +++ b/orun/app.py @@ -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 diff --git a/orun/examples/cp.py b/orun/examples/cp.py new file mode 100644 index 0000000..f60932f --- /dev/null +++ b/orun/examples/cp.py @@ -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() diff --git a/orun/extjs/__init__.py b/orun/extjs/__init__.py new file mode 100644 index 0000000..f44d217 --- /dev/null +++ b/orun/extjs/__init__.py @@ -0,0 +1,5 @@ + +from orun import js +from orun.js import client +from . import base as Ext +from .base import * diff --git a/orun/extjs/app.html b/orun/extjs/app.html new file mode 100644 index 0000000..a6dd548 --- /dev/null +++ b/orun/extjs/app.html @@ -0,0 +1,14 @@ + + + + %s + + + + + + \ No newline at end of file diff --git a/orun/extjs/base.py b/orun/extjs/base.py new file mode 100644 index 0000000..5eeefa0 --- /dev/null +++ b/orun/extjs/base.py @@ -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) diff --git a/orun/extjs/cp.py b/orun/extjs/cp.py new file mode 100644 index 0000000..f42f92f --- /dev/null +++ b/orun/extjs/cp.py @@ -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() diff --git a/orun/js.py b/orun/js.py new file mode 100644 index 0000000..2248d54 --- /dev/null +++ b/orun/js.py @@ -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)) diff --git a/orun/servers/__init__.py b/orun/servers/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/orun/servers/cp.py b/orun/servers/cp.py new file mode 100644 index 0000000..17fc7d6 --- /dev/null +++ b/orun/servers/cp.py @@ -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() diff --git a/orun/session.py b/orun/session.py new file mode 100644 index 0000000..1426344 --- /dev/null +++ b/orun/session.py @@ -0,0 +1,7 @@ + +class Session(dict): + def add_object(self, obj): + self['js_' + id(obj)] = obj + +def create_session(): + return Session() diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..27e7c55 --- /dev/null +++ b/setup.py @@ -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(), +) \ No newline at end of file