cherry 与react.js
index.html
<!DOCTYPE html> <html> <head> <link href="/static/css/style.css" rel="stylesheet"> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/react.js"></script> <script src="http://code.jquery.com/jquery-2.1.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script> </head> <body> <div id="generator"></div> <script type="text/babel" src="static/js/gen.js"></script> </body> </html>
gen.js
var StringGeneratorBox = React.createClass({ handleGenerate: function() { var length = this.state.length; this.setState(function() { $.ajax({ url: this.props.url, dataType: 'text', type: 'POST', data: { "length": length }, success: function(data) { this.setState({ length: length, string: data, mode: "edit" }); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString() ); }.bind(this) }); }); }, handleEdit: function() { var new_string = this.state.string; this.setState(function() { $.ajax({ url: this.props.url, type: 'PUT', data: { "another_string": new_string }, success: function() { this.setState({ length: new_string.length, string: new_string, mode: "edit" }); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString() ); }.bind(this) }); }); }, handleDelete: function() { this.setState(function() { $.ajax({ url: this.props.url, type: 'DELETE', success: function() { this.setState({ length: "8", string: "", mode: "create" }); }.bind(this), error: function(xhr, status, err) { console.error(this.props.url, status, err.toString() ); }.bind(this) }); }); }, handleLengthChange: function(length) { this.setState({ length: length, string: "", mode: "create" }); }, handleStringChange: function(new_string) { this.setState({ length: new_string.length, string: new_string, mode: "edit" }); }, getInitialState: function() { return { length: "8", string: "", mode: "create" }; }, render: function() { return ( <div className="stringGenBox"> <StringGeneratorForm onCreateString={this.handleGenerate} onReplaceString={this.handleEdit} onDeleteString={this.handleDelete} onLengthChange={this.handleLengthChange} onStringChange={this.handleStringChange} mode={this.state.mode} length={this.state.length} string={this.state.string}/> </div> ); } }); var StringGeneratorForm = React.createClass({ handleCreate: function(e) { e.preventDefault(); this.props.onCreateString(); }, handleReplace: function(e) { e.preventDefault(); this.props.onReplaceString(); }, handleDelete: function(e) { e.preventDefault(); this.props.onDeleteString(); }, handleLengthChange: function(e) { e.preventDefault(); var length = React.findDOMNode(this.refs.length).value.trim(); this.props.onLengthChange(length); }, handleStringChange: function(e) { e.preventDefault(); var string = React.findDOMNode(this.refs.string).value.trim(); this.props.onStringChange(string); }, render: function() { if (this.props.mode == "create") { return ( <div> <input type="text" ref="length" defaultValue="8" value={this.props.length} onChange={this.handleLengthChange} /> <button onClick={this.handleCreate}>Give it now!</button> </div> ); } else if (this.props.mode == "edit") { return ( <div> <input type="text" ref="string" value={this.props.string} onChange={this.handleStringChange} /> <button onClick={this.handleReplace}>Replace</button> <button onClick={this.handleDelete}>Delete it</button> </div> ); } return null; } }); React.render( <StringGeneratorBox url="/generator" />, document.getElementById('generator') );
Cherry
import os, os.path import random import sqlite3 import string import time import cherrypy DB_STRING = "my.db" class StringGenerator(object): @cherrypy.expose def index(self): return open('index.html') @cherrypy.expose class StringGeneratorWebService(object): @cherrypy.tools.accept(media='text/plain') def GET(self): with sqlite3.connect(DB_STRING) as c: cherrypy.session['ts'] = time.time() r = c.execute("SELECT value FROM user_string WHERE session_id=?", [cherrypy.session.id]) return r.fetchone() def POST(self, length=8): some_string = ''.join(random.sample(string.hexdigits, int(length))) with sqlite3.connect(DB_STRING) as c: cherrypy.session['ts'] = time.time() c.execute("INSERT INTO user_string VALUES (?, ?)", [cherrypy.session.id, some_string]) return some_string def PUT(self, another_string): with sqlite3.connect(DB_STRING) as c: cherrypy.session['ts'] = time.time() c.execute("UPDATE user_string SET value=? WHERE session_id=?", [another_string, cherrypy.session.id]) def DELETE(self): cherrypy.session.pop('ts', None) with sqlite3.connect(DB_STRING) as c: c.execute("DELETE FROM user_string WHERE session_id=?", [cherrypy.session.id]) def setup_database(): """ Create the `user_string` table in the database on server startup """ with sqlite3.connect(DB_STRING) as con: con.execute("CREATE TABLE user_string (session_id, value)") def cleanup_database(): """ Destroy the `user_string` table from the database on server shutdown. """ with sqlite3.connect(DB_STRING) as con: con.execute("DROP TABLE user_string") if __name__ == '__main__': conf = { '/': { 'tools.sessions.on': True, 'tools.staticdir.root': os.path.abspath(os.getcwd()) }, '/generator': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'tools.response_headers.on': True, 'tools.response_headers.headers': [('Content-Type', 'text/plain')], }, '/static': { 'tools.staticdir.on': True, 'tools.staticdir.dir': './public' } } cherrypy.engine.subscribe('start', setup_database) cherrypy.engine.subscribe('stop', cleanup_database) webapp = StringGenerator() webapp.generator = StringGeneratorWebService() cherrypy.quickstart(webapp, '/', conf)