summaryrefslogtreecommitdiff
path: root/rel/overlay/share/www/script/jquery.couch.js
diff options
context:
space:
mode:
Diffstat (limited to 'rel/overlay/share/www/script/jquery.couch.js')
-rw-r--r--rel/overlay/share/www/script/jquery.couch.js668
1 files changed, 668 insertions, 0 deletions
diff --git a/rel/overlay/share/www/script/jquery.couch.js b/rel/overlay/share/www/script/jquery.couch.js
new file mode 100644
index 00000000..ebf7d52a
--- /dev/null
+++ b/rel/overlay/share/www/script/jquery.couch.js
@@ -0,0 +1,668 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy of
+// the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+(function($) {
+ $.couch = $.couch || {};
+
+ function encodeDocId(docID) {
+ var parts = docID.split("/");
+ if (parts[0] == "_design") {
+ parts.shift();
+ return "_design/" + encodeURIComponent(parts.join('/'));
+ }
+ return encodeURIComponent(docID);
+ };
+
+ function prepareUserDoc(user_doc, new_password) {
+ if (typeof hex_sha1 == "undefined") {
+ alert("creating a user doc requires sha1.js to be loaded in the page");
+ return;
+ }
+ var user_prefix = "org.couchdb.user:";
+ user_doc._id = user_doc._id || user_prefix + user_doc.name;
+ if (new_password) {
+ // handle the password crypto
+ user_doc.salt = $.couch.newUUID();
+ user_doc.password_sha = hex_sha1(new_password + user_doc.salt);
+ }
+ user_doc.type = "user";
+ if (!user_doc.roles) {
+ user_doc.roles = []
+ }
+ return user_doc;
+ };
+
+ var uuidCache = [];
+
+ $.extend($.couch, {
+ urlPrefix: '',
+ activeTasks: function(options) {
+ ajax(
+ {url: this.urlPrefix + "/_active_tasks"},
+ options,
+ "Active task status could not be retrieved"
+ );
+ },
+
+ allDbs: function(options) {
+ ajax(
+ {url: this.urlPrefix + "/_all_dbs"},
+ options,
+ "An error occurred retrieving the list of all databases"
+ );
+ },
+
+ config: function(options, section, option, value) {
+ var req = {url: this.urlPrefix + "/_config/"};
+ if (section) {
+ req.url += encodeURIComponent(section) + "/";
+ if (option) {
+ req.url += encodeURIComponent(option);
+ }
+ }
+ if (value === null) {
+ req.type = "DELETE";
+ } else if (value !== undefined) {
+ req.type = "PUT";
+ req.data = toJSON(value);
+ req.contentType = "application/json";
+ req.processData = false
+ }
+
+ ajax(req, options,
+ "An error occurred retrieving/updating the server configuration"
+ );
+ },
+
+ session: function(options) {
+ options = options || {};
+ $.ajax({
+ type: "GET", url: this.urlPrefix + "/_session",
+ complete: function(req) {
+ var resp = $.httpData(req, "json");
+ if (req.status == 200) {
+ if (options.success) options.success(resp);
+ } else if (options.error) {
+ options.error(req.status, resp.error, resp.reason);
+ } else {
+ alert("An error occurred getting session info: " + resp.reason);
+ }
+ }
+ });
+ },
+
+ userDb : function(callback) {
+ $.couch.session({
+ success : function(resp) {
+ var userDb = $.couch.db(resp.info.authentication_db);
+ callback(userDb);
+ }
+ });
+ },
+
+ signup: function(user_doc, password, options) {
+ options = options || {};
+ // prepare user doc based on name and password
+ user_doc = prepareUserDoc(user_doc, password);
+ $.couch.userDb(function(db) {
+ db.saveDoc(user_doc, options);
+ })
+ },
+
+ login: function(options) {
+ options = options || {};
+ $.ajax({
+ 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) {
+ if (options.success) options.success(resp);
+ } else if (options.error) {
+ options.error(req.status, resp.error, resp.reason);
+ } else {
+ alert("An error occurred logging in: " + resp.reason);
+ }
+ }
+ });
+ },
+ logout: function(options) {
+ options = options || {};
+ $.ajax({
+ type: "DELETE", url: this.urlPrefix + "/_session", dataType: "json",
+ username : "_", password : "_",
+ complete: function(req) {
+ var resp = $.httpData(req, "json");
+ if (req.status == 200) {
+ if (options.success) options.success(resp);
+ } else if (options.error) {
+ options.error(req.status, resp.error, resp.reason);
+ } else {
+ alert("An error occurred logging out: " + resp.reason);
+ }
+ }
+ });
+ },
+
+ 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: this.urlPrefix + "/" + encodeURIComponent(name) + "/",
+
+ compact: function(options) {
+ $.extend(options, {successStatus: 202});
+ ajax({
+ type: "POST", url: this.uri + "_compact",
+ data: "", processData: false
+ },
+ options,
+ "The database could not be compacted"
+ );
+ },
+ viewCleanup: function(options) {
+ $.extend(options, {successStatus: 202});
+ ajax({
+ type: "POST", url: this.uri + "_view_cleanup",
+ data: "", processData: false
+ },
+ options,
+ "The views could not be cleaned up"
+ );
+ },
+ compactView: function(groupname, options) {
+ $.extend(options, {successStatus: 202});
+ ajax({
+ type: "POST", url: this.uri + "_compact/" + groupname,
+ data: "", processData: false
+ },
+ options,
+ "The view could not be compacted"
+ );
+ },
+ create: function(options) {
+ $.extend(options, {successStatus: 201});
+ ajax({
+ type: "PUT", url: this.uri, contentType: "application/json",
+ data: "", processData: false
+ },
+ options,
+ "The database could not be created"
+ );
+ },
+ drop: function(options) {
+ ajax(
+ {type: "DELETE", url: this.uri},
+ options,
+ "The database could not be deleted"
+ );
+ },
+ info: function(options) {
+ ajax(
+ {url: this.uri},
+ options,
+ "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) {
+ 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"
+ );
+ },
+ allDesignDocs: function(options) {
+ this.allDocs($.extend({startkey:"_design", endkey:"_design0"}, options));
+ },
+ allApps: function(options) {
+ options = options || {};
+ var self = this;
+ if (options.eachApp) {
+ this.allDesignDocs({
+ success: function(resp) {
+ $.each(resp.rows, function() {
+ self.openDoc(this.id, {
+ success: function(ddoc) {
+ var index, appPath, appName = ddoc._id.split('/');
+ appName.shift();
+ appName = appName.join('/');
+ index = ddoc.couchapp && ddoc.couchapp.index;
+ if (index) {
+ appPath = ['', name, ddoc._id, index].join('/');
+ } else if (ddoc._attachments && ddoc._attachments["index.html"]) {
+ appPath = ['', name, ddoc._id, "index.html"].join('/');
+ }
+ if (appPath) options.eachApp(appName, appPath, ddoc);
+ }
+ });
+ });
+ }
+ });
+ } else {
+ 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",
+ ajaxOptions
+ );
+ },
+ saveDoc: function(doc, options) {
+ options = options || {};
+ var db = this;
+ var beforeSend = fullCommit(options);
+ if (doc._id === undefined) {
+ var method = "POST";
+ var uri = this.uri;
+ } else {
+ 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 == 200 || req.status == 201 || req.status == 202) {
+ doc._id = resp.id;
+ doc._rev = resp.rev;
+ 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 {
+ alert("The document could not be saved: " + resp.reason);
+ }
+ }
+ });
+ },
+ bulkSave: function(docs, options) {
+ var beforeSend = fullCommit(options);
+ $.extend(options, {successStatus: 201, beforeSend : beforeSend});
+ ajax({
+ type: "POST",
+ url: this.uri + "_bulk_docs" + encodeOptions(options),
+ contentType: "application/json", data: toJSON(docs)
+ },
+ options,
+ "The documents could not be saved"
+ );
+ },
+ removeDoc: function(doc, options) {
+ ajax({
+ type: "DELETE",
+ url: this.uri +
+ encodeDocId(doc._id) +
+ encodeOptions({rev: doc._rev})
+ },
+ options,
+ "The document could not be deleted"
+ );
+ },
+ 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) {
+ if (options.success) options.success(resp);
+ } else if (options.error) {
+ options.error(req.status, resp.error, resp.reason);
+ } else {
+ alert("The document could not be copied: " + resp.reason);
+ }
+ }
+ });
+ ajax({
+ type: "COPY",
+ url: this.uri + encodeDocId(docId)
+ },
+ options,
+ "The document could not be copied",
+ ajaxOptions
+ );
+ },
+ query: function(mapFun, reduceFun, language, options) {
+ language = language || "javascript";
+ if (typeof(mapFun) !== "string") {
+ mapFun = mapFun.toSource ? mapFun.toSource() : "(" + mapFun.toString() + ")";
+ }
+ var body = {language: language, map: mapFun};
+ if (reduceFun != null) {
+ if (typeof(reduceFun) !== "string")
+ reduceFun = reduceFun.toSource ? reduceFun.toSource() : "(" + reduceFun.toString() + ")";
+ body.reduce = reduceFun;
+ }
+ ajax({
+ type: "POST",
+ url: this.uri + "_temp_view" + encodeOptions(options),
+ contentType: "application/json", data: toJSON(body)
+ },
+ options,
+ "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 || {};
+ 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/" + name[0] +
+ "/_view/" + name[1] + encodeOptions(options)
+ },
+ 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
+ );
+ }
+ };
+ },
+
+ encodeDocId: encodeDocId,
+
+ info: function(options) {
+ ajax(
+ {url: this.urlPrefix + "/"},
+ options,
+ "Server information could not be retrieved"
+ );
+ },
+
+ replicate: function(source, target, ajaxOptions, repOpts) {
+ repOpts = $.extend({source: source, target: target}, repOpts);
+ if (repOpts.continuous) {
+ ajaxOptions.successStatus = 202;
+ }
+ ajax({
+ type: "POST", url: this.urlPrefix + "/_replicate",
+ data: JSON.stringify(repOpts),
+ contentType: "application/json"
+ },
+ ajaxOptions,
+ "Replication failed"
+ );
+ },
+
+ newUUID: function(cacheNum) {
+ if (cacheNum === undefined) {
+ cacheNum = 1;
+ }
+ if (!uuidCache.length) {
+ ajax({url: this.urlPrefix + "/_uuids", data: {count: cacheNum}, async: false}, {
+ success: function(resp) {
+ uuidCache = resp.uuids
+ }
+ },
+ "Failed to retrieve UUID batch."
+ );
+ }
+ 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", 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) {
+ 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 && resp.error || errorMessage, resp && resp.reason || "no response");
+ } else {
+ alert(errorMessage + ": " + resp.reason);
+ }
+ }
+ }, 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", "beforeSuccess", "ajaxStart"]) >= 0)
+ continue;
+ var value = options[name];
+ if ($.inArray(name, ["key", "startkey", "endkey"]) >= 0) {
+ value = toJSON(value);
+ }
+ buf.push(encodeURIComponent(name) + "=" + encodeURIComponent(value));
+ }
+ }
+ return buf.length ? "?" + buf.join("&") : "";
+ }
+
+ function toJSON(obj) {
+ return obj !== null ? JSON.stringify(obj) : null;
+ }
+
+})(jQuery);