diff options
Diffstat (limited to 'share/www/script/jquery.couch.js')
-rw-r--r-- | share/www/script/jquery.couch.js | 294 |
1 files changed, 253 insertions, 41 deletions
diff --git a/share/www/script/jquery.couch.js b/share/www/script/jquery.couch.js index 7e8a0236..114e5801 100644 --- a/share/www/script/jquery.couch.js +++ b/share/www/script/jquery.couch.js @@ -28,7 +28,7 @@ return; } var user_prefix = "org.couchdb.user:"; - user_doc._id = user_doc._id || user_prefix + user_doc.username; + user_doc._id = user_doc._id || user_prefix + user_doc.name; if (new_password) { // handle the password crypto user_doc.salt = $.couch.newUUID(); @@ -36,17 +36,18 @@ } user_doc.type = "user"; if (!user_doc.roles) { - user_doc.roles = [] + user_doc.roles = []; } return user_doc; }; - uuidCache = []; + var uuidCache = []; $.extend($.couch, { + urlPrefix: '', activeTasks: function(options) { ajax( - {url: "/_active_tasks"}, + {url: this.urlPrefix + "/_active_tasks"}, options, "Active task status could not be retrieved" ); @@ -54,14 +55,14 @@ allDbs: function(options) { ajax( - {url: "/_all_dbs"}, + {url: this.urlPrefix + "/_all_dbs"}, options, "An error occurred retrieving the list of all databases" ); }, config: function(options, section, option, value) { - var req = {url: "/_config/"}; + var req = {url: this.urlPrefix + "/_config/"}; if (section) { req.url += encodeURIComponent(section) + "/"; if (option) { @@ -74,7 +75,7 @@ req.type = "PUT"; req.data = toJSON(value); req.contentType = "application/json"; - req.processData = false + req.processData = false; } ajax(req, options, @@ -85,7 +86,7 @@ session: function(options) { options = options || {}; $.ajax({ - type: "GET", url: "/_session", + type: "GET", url: this.urlPrefix + "/_session", complete: function(req) { var resp = $.httpData(req, "json"); if (req.status == 200) { @@ -102,7 +103,7 @@ userDb : function(callback) { $.couch.session({ success : function(resp) { - var userDb = $.couch.db(resp.info.user_db); + var userDb = $.couch.db(resp.info.authentication_db); callback(userDb); } }); @@ -114,14 +115,14 @@ user_doc = prepareUserDoc(user_doc, password); $.couch.userDb(function(db) { db.saveDoc(user_doc, options); - }) + }); }, login: function(options) { options = options || {}; $.ajax({ - type: "POST", url: "/_session", dataType: "json", - data: {username: options.username, password: options.password}, + type: "POST", url: this.urlPrefix + "/_session", dataType: "json", + data: {name: options.name, password: options.password}, complete: function(req) { var resp = $.httpData(req, "json"); if (req.status == 200) { @@ -137,7 +138,7 @@ logout: function(options) { options = options || {}; $.ajax({ - type: "DELETE", url: "/_session", dataType: "json", + type: "DELETE", url: this.urlPrefix + "/_session", dataType: "json", username : "_", password : "_", complete: function(req) { var resp = $.httpData(req, "json"); @@ -152,10 +153,28 @@ }); }, - db: function(name) { + db: function(name, db_opts) { + db_opts = db_opts || {}; + var rawDocs = {}; + function maybeApplyVersion(doc) { + if (doc._id && doc._rev && rawDocs[doc._id] && rawDocs[doc._id].rev == doc._rev) { + // todo: can we use commonjs require here? + if (typeof Base64 == "undefined") { + alert("please include /_utils/script/base64.js in the page for base64 support"); + return false; + } else { + doc._attachments = doc._attachments || {}; + doc._attachments["rev-"+doc._rev.split("-")[0]] = { + content_type :"application/json", + data : Base64.encode(rawDocs[doc._id].raw) + }; + return true; + } + } + }; return { name: name, - uri: "/" + encodeURIComponent(name) + "/", + uri: this.urlPrefix + "/" + encodeURIComponent(name) + "/", compact: function(options) { $.extend(options, {successStatus: 202}); @@ -211,9 +230,79 @@ "Database information could not be retrieved" ); }, + changes: function(since, options) { + options = options || {}; + // set up the promise object within a closure for this handler + var timeout = 100, db = this, active = true, + listeners = [], + promise = { + onChange : function(fun) { + listeners.push(fun); + }, + stop : function() { + active = false; + } + }; + // call each listener when there is a change + function triggerListeners(resp) { + $.each(listeners, function() { + this(resp); + }); + }; + // when there is a change, call any listeners, then check for another change + options.success = function(resp) { + timeout = 100; + if (active) { + since = resp.last_seq; + triggerListeners(resp); + getChangesSince(); + }; + }; + options.error = function() { + if (active) { + setTimeout(getChangesSince, timeout); + timeout = timeout * 2; + } + }; + // actually make the changes request + function getChangesSince() { + var opts = $.extend({heartbeat : 10 * 1000}, options, { + feed : "longpoll", + since : since + }); + ajax( + {url: db.uri + "_changes"+encodeOptions(opts)}, + options, + "Error connecting to "+db.uri+"/_changes." + ); + } + // start the first request + if (since) { + getChangesSince(); + } else { + db.info({ + success : function(info) { + since = info.update_seq; + getChangesSince(); + } + }); + } + return promise; + }, allDocs: function(options) { - ajax( - {url: this.uri + "_all_docs" + encodeOptions(options)}, + var type = "GET"; + var data = null; + if (options["keys"]) { + type = "POST"; + var keys = options["keys"]; + delete options["keys"]; + data = toJSON({ "keys": keys }); + } + ajax({ + type: type, + data: data, + url: this.uri + "_all_docs" + encodeOptions(options) + }, options, "An error occurred retrieving a list of all documents" ); @@ -246,10 +335,32 @@ } }); } else { - alert("please provide an eachApp function for allApps()"); + alert("Please provide an eachApp function for allApps()"); } }, openDoc: function(docId, options, ajaxOptions) { + options = options || {}; + if (db_opts.attachPrevRev || options.attachPrevRev) { + $.extend(options, { + beforeSuccess : function(req, doc) { + rawDocs[doc._id] = { + rev : doc._rev, + raw : req.responseText + }; + } + }); + } else { + $.extend(options, { + beforeSuccess : function(req, doc) { + if (doc["jquery.couch.attachPrevRev"]) { + rawDocs[doc._id] = { + rev : doc._rev, + raw : req.responseText + }; + } + } + }); + } ajax({url: this.uri + encodeDocId(docId) + encodeOptions(options)}, options, "The document could not be retrieved", @@ -258,6 +369,8 @@ }, saveDoc: function(doc, options) { options = options || {}; + var db = this; + var beforeSend = fullCommit(options); if (doc._id === undefined) { var method = "POST"; var uri = this.uri; @@ -265,16 +378,28 @@ var method = "PUT"; var uri = this.uri + encodeDocId(doc._id); } + var versioned = maybeApplyVersion(doc); $.ajax({ type: method, url: uri + encodeOptions(options), contentType: "application/json", dataType: "json", data: toJSON(doc), + beforeSend : beforeSend, complete: function(req) { var resp = $.httpData(req, "json"); - if (req.status == 201) { + if (req.status == 200 || req.status == 201 || req.status == 202) { doc._id = resp.id; doc._rev = resp.rev; - if (options.success) options.success(resp); + if (versioned) { + db.openDoc(doc._id, { + attachPrevRev : true, + success : function(d) { + doc._attachments = d._attachments; + if (options.success) options.success(resp); + } + }); + } else { + if (options.success) options.success(resp); + } } else if (options.error) { options.error(req.status, resp.error, resp.reason); } else { @@ -284,10 +409,12 @@ }); }, bulkSave: function(docs, options) { - $.extend(options, {successStatus: 201}); + var beforeSend = fullCommit(options); + $.extend(options, {successStatus: 201, beforeSend : beforeSend}); ajax({ type: "POST", - url: this.uri + "_bulk_docs" + encodeOptions(options) + url: this.uri + "_bulk_docs" + encodeOptions(options), + contentType: "application/json", data: toJSON(docs) }, options, "The documents could not be saved" @@ -304,13 +431,27 @@ "The document could not be deleted" ); }, - copyDoc: function(doc, options, ajaxOptions) { + bulkRemove: function(docs, options){ + docs.docs = $.each( + docs.docs, function(i, doc){ + doc._deleted = true; + } + ); + $.extend(options, {successStatus: 201}); + ajax({ + type: "POST", + url: this.uri + "_bulk_docs" + encodeOptions(options), + data: toJSON(docs) + }, + options, + "The documents could not be deleted" + ); + }, + copyDoc: function(docId, options, ajaxOptions) { ajaxOptions = $.extend(ajaxOptions, { complete: function(req) { var resp = $.httpData(req, "json"); if (req.status == 201) { - doc._id = resp.id; - doc._rev = resp.rev; if (options.success) options.success(resp); } else if (options.error) { options.error(req.status, resp.error, resp.reason); @@ -321,9 +462,7 @@ }); ajax({ type: "COPY", - url: this.uri + - encodeDocId(doc._id) + - encodeOptions({rev: doc._rev}) + url: this.uri + encodeDocId(docId) }, options, "The document could not be copied", @@ -350,6 +489,26 @@ "An error occurred querying the database" ); }, + list: function(list, view, options) { + var list = list.split('/'); + var options = options || {}; + var type = 'GET'; + var data = null; + if (options['keys']) { + type = 'POST'; + var keys = options['keys']; + delete options['keys']; + data = toJSON({'keys': keys }); + } + ajax({ + type: type, + data: data, + url: this.uri + '_design/' + list[0] + + '/_list/' + list[1] + '/' + view + encodeOptions(options) + }, + options, 'An error occured accessing the list' + ); + }, view: function(name, options) { var name = name.split('/'); var options = options || {}; @@ -369,6 +528,25 @@ }, options, "An error occurred accessing the view" ); + }, + getDbProperty: function(propName, options, ajaxOptions) { + ajax({url: this.uri + propName + encodeOptions(options)}, + options, + "The property could not be retrieved", + ajaxOptions + ); + }, + + setDbProperty: function(propName, propValue, options, ajaxOptions) { + ajax({ + type: "PUT", + url: this.uri + propName + encodeOptions(options), + data : JSON.stringify(propValue) + }, + options, + "The property could not be updated", + ajaxOptions + ); } }; }, @@ -377,19 +555,23 @@ info: function(options) { ajax( - {url: "/"}, + {url: this.urlPrefix + "/"}, options, "Server information could not be retrieved" ); }, - replicate: function(source, target, options) { + replicate: function(source, target, ajaxOptions, repOpts) { + repOpts = $.extend({source: source, target: target}, repOpts); + if (repOpts.continuous) { + ajaxOptions.successStatus = 202; + } ajax({ - type: "POST", url: "/_replicate", - data: JSON.stringify({source: source, target: target}), + type: "POST", url: this.urlPrefix + "/_replicate", + data: JSON.stringify(repOpts), contentType: "application/json" }, - options, + ajaxOptions, "Replication failed" ); }, @@ -399,9 +581,9 @@ cacheNum = 1; } if (!uuidCache.length) { - ajax({url: "/_uuids", data: {count: cacheNum}, async: false}, { + ajax({url: this.urlPrefix + "/_uuids", data: {count: cacheNum}, async: false}, { success: function(resp) { - uuidCache = resp.uuids + uuidCache = resp.uuids; } }, "Failed to retrieve UUID batch." @@ -409,21 +591,40 @@ } return uuidCache.shift(); } - }); function ajax(obj, options, errorMessage, ajaxOptions) { options = $.extend({successStatus: 200}, options); + ajaxOptions = $.extend({contentType: "application/json"}, ajaxOptions); errorMessage = errorMessage || "Unknown error"; - $.ajax($.extend($.extend({ - type: "GET", dataType: "json", + type: "GET", dataType: "json", cache : !$.browser.msie, + beforeSend: function(xhr){ + if(ajaxOptions && ajaxOptions.headers){ + for (var header in ajaxOptions.headers){ + xhr.setRequestHeader(header, ajaxOptions.headers[header]); + } + } + }, complete: function(req) { - var resp = $.httpData(req, "json"); + try { + var resp = $.httpData(req, "json"); + } catch(e) { + if (options.error) { + options.error(req.status, req, e); + } else { + alert(errorMessage + ": " + e); + } + return; + } + if (options.ajaxStart) { + options.ajaxStart(resp); + } if (req.status == options.successStatus) { + if (options.beforeSuccess) options.beforeSuccess(req, resp); if (options.success) options.success(resp); } else if (options.error) { - options.error(req.status, resp.error, resp.reason); + options.error(req.status, resp && resp.error || errorMessage, resp && resp.reason || "no response"); } else { alert(errorMessage + ": " + resp.reason); } @@ -431,13 +632,24 @@ }, obj), ajaxOptions)); } + function fullCommit(options) { + var options = options || {}; + if (typeof options.ensure_full_commit !== "undefined") { + var commit = options.ensure_full_commit; + delete options.ensure_full_commit; + return function(xhr) { + xhr.setRequestHeader("X-Couch-Full-Commit", commit.toString()); + }; + } + }; + // Convert a options object to an url query string. // ex: {key:'value',key2:'value2'} becomes '?key="value"&key2="value2"' function encodeOptions(options) { var buf = []; if (typeof(options) === "object" && options !== null) { for (var name in options) { - if ($.inArray(name, ["error", "success"]) >= 0) + if ($.inArray(name, ["error", "success", "beforeSuccess", "ajaxStart"]) >= 0) continue; var value = options[name]; if ($.inArray(name, ["key", "startkey", "endkey"]) >= 0) { |