Skip to content
This repository has been archived by the owner on Sep 28, 2018. It is now read-only.

Commit

Permalink
Add JSON serializer/desirializer for CouchDB dcument forms.
Browse files Browse the repository at this point in the history
Add user profile creation.
  • Loading branch information
yssk22 committed Dec 3, 2009
1 parent 46136ab commit ff47552
Show file tree
Hide file tree
Showing 14 changed files with 532 additions and 197 deletions.
Expand Up @@ -11,6 +11,93 @@
}
});

jQuery.fn.clear = function(){
this.each(function(){
var dom = this;
var tag = dom.tagName.toLowerCase();
var type = dom.type;
if( type == "text" || type == "password" || tag == "textarea"){
jQuery(dom).val("");
}else if( type == "checkbox" || type == "radio" ){
jQuery(dom).attr("checked", "");
}else{
dom.selectedIndex = -1;
}
});
},

jQuery.fn.serializeJson = function(options){
var opts = jQuery.extend({fields: []}, options);
var form = this;
var doc = {};

function setDocVal(to, path_name, value){
var paths = path_name.split("-");
var field = to, member = paths.shift();
while (paths.length > 0) {
field[member] = field[member] || {};
field = field[member];
member = paths.shift();
}
field[member] = value;
}

// for input field
form.find("input").each(function(){
var elm = jQuery(this);
var val;
switch(elm.attr("type")){
case "radio":
case "checkbox":
if( elm.attr("checked") ){
val = JSON.parse(elm.val());
}
break;
default: // hidden or text
val = elm.val();
break;
}
if(!val){ return; }
setDocVal(doc, elm.attr("name"), val);
});

// for textarea
form.find("textarea").each(function(){
var elm = jQuery(this);
var val = elm.val();
if(!val){ return; }
setDocVal(doc, elm.attr("name"), val);
});
// for selection
// special crayon_type : date_select
form.find("select[crayon_type='date_select_year']").each(function(){
var elm = jQuery(this);
var y, m, d;
y = elm.val();
var date_name = elm.attr("name").split("-");
date_name[date_name.length-1] = "month";
m = form.find("select[name='" + date_name.join("-") + "']").val();
date_name[date_name.length-1] = "day";
d = form.find("select[name='" + date_name.join("-") + "']").val();
if(!y){ return; }
if(!m){ return; }
if(!d){ return; }
date_name.splice(date_name.length - 1);
setDocVal(doc, date_name.join("-"), new Date(y + "/" + m + "/" + d));
});
// normal select
form.find("select").each(function(){
var elm = jQuery(this);
// skip crayon type
if( elm.attr("crayon_type") ){ return; }

var val = elm.val();
if(!val){ return; }
setDocVal(doc, elm.attr("name"), val);
});
return doc;
},

jQuery.fn.nowLoading = function(options){
var opts;
if( options == "clear" ){
Expand Down
Expand Up @@ -14,11 +14,13 @@ ACCOUNT_RULES = {

jQuery(function(){
jQuery("#tabs").tabs();
jQuery("div#login form").submit(function(){
jQuery("div#login form").submit(function(e){
e.preventDefault();
login(jQuery(this));
return false;
});
jQuery("div#signup form").submit(function(){
jQuery("div#signup form").submit(function(e){
e.preventDefault();
signUp(jQuery(this));
return false;
});
Expand Down
@@ -0,0 +1,61 @@
PROFILE_RULES = {
"displayName-formatted": {
required : true
}
};

function alertError(status, error, reason){
alert("[" + status + ":" + error + "] " + reason);
}

function onSubmitUpdateProfile(e){
var f = jQuery("form#update_profile");
e.preventDefault();
var doc = f.serializeJson();
if( f.valid() ){
f.nowLoading({message: "Updating your profile ..."});
Site.CouchApp.db.saveDoc(doc, {
success: function(resp){
alert("OK");
f.find("input[name='_rev']").val(doc._rev);
f.nowLoading("clear");
},
error: function(status, error, reason){
alertError(status, error, reason);
f.nowLoading("clear");
}
});
}
return false;
}

function onSubmitCreateProfile(e){
var f = jQuery("form#create_profile");
e.preventDefault();
var doc = f.serializeJson();
if( f.valid() ){
f.nowLoading({message: "Submitting your profile ..."});
Site.CouchApp.db.saveDoc(doc, {
success: function(resp){
f.nowLoading({message: "Building your page ..."});
Site.go(Site.CouchApp.showPath("profile", doc._id));
},
error: function(status, error, reason){
alertError(status, error, reason);
f.nowLoading("clear");
}
});
}
return false;
}


$.CouchApp(function(app){
var f = jQuery("form#create_profile");
f.validate(PROFILE_RULES);
f.submit(onSubmitCreateProfile);

f = jQuery("form#update_profile");
f.validate(PROFILE_RULES);
f.submit(onSubmitUpdateProfile);
});
@@ -1,10 +1,9 @@
WebJourney.Site = WebJourney.Site || function(){
this.initialize.apply(this, arguments);
};
WebJourney.Site.Foo = "bar";

WebJourney.Site.prototype = {
initialize: function(app){
initialize: function(app, current_user){
var self = this;
var path = window.location.pathname.split("/");
this.CouchApp = app;
Expand All @@ -14,6 +13,15 @@ WebJourney.Site.prototype = {
this._js_root = [this._app_root, "javascripts"].join("/");
this._css_root = [this._app_root, "stylesheets"].join("/");
this._domain = window.location.host;
if( current_user ){
this._user = current_user;
}else{
this._user = {
db: ["", path[1]].join("/"),
name: "",
roles: []
};
}
},

logout: function(){
Expand All @@ -39,11 +47,15 @@ WebJourney.Site.prototype = {

getUserId : function(username){
// domain prefiexed user id
return this._domain + ":" + username;
if(username){
return this._domain + ":" + username;
}
else{
return this._domain + ":" + this._user.name;
}
},

getCurrentUser : function(){
return this._user;
}
};

Site = null;
$.CouchApp(function(app){
Site = new WebJourney.Site(app);
});
Expand Up @@ -33,10 +33,11 @@ WebJourney.Util.toQueryString = function(params){
return str;
};


WebJourney.Util.log = function(message){
if( window.console && window.console.log ){
window.console.log(message);
}
};

window.log = WebJourney.Util.log;
var log = WebJourney.Util.log;
22 changes: 2 additions & 20 deletions relax/containers/webjourney/lib/helpers/util.js
@@ -1,21 +1,3 @@
function html_escape(s){
return s.toString().replace(/&/g, "&").
replace(/\"/g, """).
replace(/\'/g, "'").
replace(/</g, "&lt;").
replace(/>/g, "&gt;");
}

function h(s){
return html_escape(s);
}

function json_escape(s){
return s.toString().relace(/&/g, "\\u0026").
replace(/</g, "\\u003c").
replace(/>/g, "\\u003e");
}

function j(s){
return json_escape(s);
function clearButton(selector){
return '<button type="button" onclick=\'jQuery(' + h(toJSON(selector)) + ').clear()\'>Clear</button>';
}
6 changes: 6 additions & 0 deletions relax/containers/webjourney/models/profile.json
@@ -0,0 +1,6 @@
{
"type" : "Person",
"displayName" : {
"formatted" : "Your Name"
}
}
54 changes: 54 additions & 0 deletions relax/containers/webjourney/shows/profile.js
@@ -0,0 +1,54 @@
function(doc, req) {
// !code vendor/couchapp/path.js
// !code lib/helpers/securityToken.js
// !code lib/helpers/util.js
// !code vendor/crayon/lib/escape.js
// !code vendor/crayon/lib/template.js
// !code vendor/crayon/lib/error.js
// !code vendor/crayon/lib/form.js

// !json models.profile
// !json templates.site
// !json templates.profile

var bindings = {
request : req,
current_user : req.userCtx,
assetPath : assetPath(),
site: {
title: "Profile",
javascripts: [
"profile.js"
]
}
};


if(doc && doc.type == "Person"){
bindings["profile"] = doc;
return render(templates.site.header, bindings) +
render(templates.profile.main, bindings) +
render(templates.site.footer, bindings);
}else if(req.docId){
var userid = req.docId.split(":");
var domain = userid[0], username = userid[1];
if( domain == req.headers["Host"] || domain == req.headers["X-Forwarded-Host"] ){
if( username == req.userCtx.name ){
bindings["profile"] = models.profile;
bindings["profile"]["_id"] = req.docId;
return render(templates.site.header, bindings) +
render(templates.profile.not_found, bindings) +
render(templates.site.footer, bindings);
}else{
// TODO HTML rendering
return render_error(FORBIDDEN);
}
}else{
// TODO HTML rendering
return render_error(NOT_FOUND);
}
}else{
// TODO HTML rendering
return render_error(NOT_FOUND);
}
}
35 changes: 35 additions & 0 deletions relax/containers/webjourney/templates/profile/form.html
@@ -0,0 +1,35 @@
<%= hidden_field(profile, "type") %>
<%= hidden_field(profile, "_id") %>
<%= hidden_field(profile, "_rev") %>
<fieldset>
<div>
<label for="displayName-formatted">Display Name<em>*</em></label>
<div>
<%= text_field(profile, "displayName-formatted", {class: "required"} )%>
</div>
</div>
<div>
<label for="birthday-year">Birthday</label>
<div>
<%= date_select(profile, "birthday", {
"include_blank" : true
}) %>
<%= clearButton("select[name='birthday-year']") %>
</div>
</div>
<div>
<label for="gender">Gender</label>
<div>
<%= radio_button(profile, "gender", "male") %> Male
<%= radio_button(profile, "gender", "female") %> Female
<%= clearButton("input[name='gender']") %>
</div>
</div>
<div>
<label for="aboutMe">About Me</label>
<div>
<%= text_area(profile, "aboutMe", {rows: 8, cols:80})%>
</div>
<p class="note">Markdown format is available.</p>
</div>
</fieldset>
29 changes: 29 additions & 0 deletions relax/containers/webjourney/templates/profile/main.html
@@ -0,0 +1,29 @@
<div id="main">
<div class="ui-widget ui-widget-content ui-corner-all gadget">
<div class="ui-widget ui-state-default ui-widget-header ui-corner-all gadget-title-bar">
<div class="gadget-title-bar-label">
<span>Update Your Profile</span>
</div>
</div>
<div class="ui-widget gadget-body">
<div class="gadget-embedded-content">
<div id="profile_editor">
<div class="sform">
<form id="update_profile" method="POST" action="#create_profile">
<p class="legend">
<strong>Note:</strong>
You can update your own profile.
Required fields are marked as <em>*</em>.
</p>
<%= render(templates.profile.form, {profile: profile}) %>
<div class="buttonrow">
<button type="submit">Update</button>
</div>
</form>
</div>
</div><!-- register -->
</div><!-- tabs -->
</div>
</div>
</div>
</div>

0 comments on commit ff47552

Please sign in to comment.