summaryrefslogtreecommitdiff
path: root/rel/overlay/share/www/script/futon.js
diff options
context:
space:
mode:
Diffstat (limited to 'rel/overlay/share/www/script/futon.js')
-rw-r--r--rel/overlay/share/www/script/futon.js471
1 files changed, 471 insertions, 0 deletions
diff --git a/rel/overlay/share/www/script/futon.js b/rel/overlay/share/www/script/futon.js
new file mode 100644
index 00000000..b15a5eec
--- /dev/null
+++ b/rel/overlay/share/www/script/futon.js
@@ -0,0 +1,471 @@
+// 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.
+
+// $$ inspired by @wycats: http://yehudakatz.com/2009/04/20/evented-programming-with-jquery/
+function $$(node) {
+ var data = $(node).data("$$");
+ if (data) {
+ return data;
+ } else {
+ data = {};
+ $(node).data("$$", data);
+ return data;
+ }
+};
+
+(function($) {
+
+ function Session() {
+
+ function doLogin(name, password, callback) {
+ $.couch.login({
+ name : name,
+ password : password,
+ success : function() {
+ $.futon.session.sidebar();
+ callback();
+ },
+ error : function(code, error, reason) {
+ $.futon.session.sidebar();
+ callback({name : "Error logging in: "+reason});
+ }
+ });
+ };
+
+ function doSignup(name, password, callback, runLogin) {
+ $.couch.signup({
+ name : name
+ }, password, {
+ success : function() {
+ if (runLogin) {
+ doLogin(name, password, callback);
+ } else {
+ callback();
+ }
+ },
+ error : function(status, error, reason) {
+ $.futon.session.sidebar();
+ if (error == "conflict") {
+ callback({name : "Name '"+name+"' is taken"});
+ } else {
+ callback({name : "Signup error: "+reason});
+ }
+ }
+ });
+ };
+
+ function validateUsernameAndPassword(data, callback) {
+ if (!data.name || data.name.length == 0) {
+ callback({name: "Please enter a name."});
+ return false;
+ };
+ if (!data.password || data.password.length == 0) {
+ callback({password: "Please enter a password."});
+ return false;
+ };
+ return true;
+ };
+
+ function createAdmin() {
+ $.showDialog("dialog/_create_admin.html", {
+ submit: function(data, callback) {
+ if (!validateUsernameAndPassword(data, callback)) return;
+ $.couch.config({
+ success : function() {
+ doLogin(data.name, data.password, function(errors) {
+ if(!$.isEmptyObject(errors)) {
+ callback(errors);
+ return;
+ }
+ doSignup(data.name, null, function(errors) {
+ if (errors && errors.name && errors.name.indexOf && errors.name.indexOf("taken") == -1) {
+ callback(errors);
+ } else {
+ callback();
+ }
+ }, false);
+ });
+ }
+ }, "admins", data.name, data.password);
+ }
+ });
+ return false;
+ };
+
+ function login() {
+ $.showDialog("dialog/_login.html", {
+ submit: function(data, callback) {
+ if (!validateUsernameAndPassword(data, callback)) return;
+ doLogin(data.name, data.password, callback);
+ }
+ });
+ return false;
+ };
+
+ function logout() {
+ $.couch.logout({
+ success : function(resp) {
+ $.futon.session.sidebar();
+ }
+ })
+ };
+
+ function signup() {
+ $.showDialog("dialog/_signup.html", {
+ submit: function(data, callback) {
+ if (!validateUsernameAndPassword(data, callback)) return;
+ doSignup(data.name, data.password, callback, true);
+ }
+ });
+ return false;
+ };
+
+ this.setupSidebar = function() {
+ $("#userCtx .login").click(login);
+ $("#userCtx .logout").click(logout);
+ $("#userCtx .signup").click(signup);
+ $("#userCtx .createadmin").click(createAdmin);
+ };
+
+ this.sidebar = function() {
+ // get users db info?
+ $("#userCtx span").hide();
+ $.couch.session({
+ success : function(r) {
+ var userCtx = r.userCtx;
+ $$("#userCtx").userCtx = userCtx;
+ if (userCtx.name) {
+ $("#userCtx .name").text(userCtx.name).attr({href : $.couch.urlPrefix + "/_utils/document.html?"+encodeURIComponent(r.info.authentication_db)+"/org.couchdb.user%3A"+encodeURIComponent(userCtx.name)});
+ if (userCtx.roles.indexOf("_admin") != -1) {
+ $("#userCtx .loggedinadmin").show();
+ } else {
+ $("#userCtx .loggedin").show();
+ }
+ } else if (userCtx.roles.indexOf("_admin") != -1) {
+ $("#userCtx .adminparty").show();
+ } else {
+ $("#userCtx .loggedout").show();
+ };
+ }
+ })
+ };
+ };
+
+ function Navigation() {
+ var nav = this;
+ this.loaded = false;
+ this.eventHandlers = {
+ load: []
+ };
+
+ this.ready = function(callback) {
+ if (callback) {
+ if (this.loaded) {
+ callback.apply(this);
+ }
+ this.eventHandlers["load"].push(callback);
+ } else {
+ this.loaded = true;
+ callbacks = this.eventHandlers["load"];
+ for (var i = 0; i < callbacks.length; i++) {
+ callbacks[i].apply(this);
+ }
+ }
+ }
+
+ this.addDatabase = function(name) {
+ var current = $.futon.storage.get("recent", "");
+ var recentDbs = current ? current.split(",") : [];
+ if ($.inArray(name, recentDbs) == -1) {
+ recentDbs.unshift(name);
+ if (recentDbs.length > 10) recentDbs.length = 10;
+ $.futon.storage.set("recent", recentDbs.join(","));
+ this.updateDatabases();
+ }
+ }
+
+ this.removeDatabase = function(name) {
+ // remove database from recent databases list
+ var current = $.futon.storage.get("recent", "");
+ var recentDbs = current ? current.split(",") : [];
+ var recentIdx = $.inArray(name, recentDbs);
+ if (recentIdx >= 0) {
+ recentDbs.splice(recentIdx, 1);
+ $.futon.storage.set("recent", recentDbs.join(","));
+ this.updateDatabases();
+ }
+ }
+
+ this.updateDatabases = function() {
+ var selection = null;
+ $("#dbs .selected a").each(function() {
+ selection = [this.pathname, this.search];
+ });
+ $("#dbs").empty();
+ var recentDbs = $.futon.storage.get("recent").split(",");
+ recentDbs.sort();
+ $.each(recentDbs, function(idx, name) {
+ if (name) {
+ $("#dbs").append("<li>" +
+ "<button class='remove' title='Remove from list' value='" + name + "'></button>" +
+ "<a href='database.html?" + encodeURIComponent(name) + "' title='" + name + "'>" + name +
+ "</a></li>");
+ }
+ });
+ if (selection) {
+ this.updateSelection(selection[0], selection[1]);
+ }
+ $("#dbs button.remove").click(function() {
+ nav.removeDatabase(this.value);
+ return false;
+ });
+ }
+
+ this.updateSelection = function(path, queryString) {
+ function fixupPath(path) { // hack for IE/Win
+ return (path.charAt(0) != "/") ? ("/" + path) : path;
+ }
+ if (!path) {
+ path = location.pathname;
+ if (!queryString) {
+ queryString = location.search;
+ }
+ } else if (!queryString) {
+ queryString = "";
+ }
+ var href = fixupPath(path + queryString);
+ $("#nav li").removeClass("selected");
+ $("#nav li a").each(function() {
+ if (fixupPath(this.pathname) + this.search != href) return;
+ $(this).parent("li").addClass("selected").parents("li").addClass("selected");
+ });
+ }
+
+ this.toggle = function(speed) {
+ if (speed === undefined) {
+ speed = 500;
+ }
+ var sidebar = $("#sidebar").stop(true, true);
+ var hidden = !$(sidebar).is(".hidden");
+
+ $("#wrap").animate({
+ marginRight: hidden ? 0 : 210
+ }, speed, function() {
+ $(document.body).toggleClass("fullwidth", hidden);
+ });
+ sidebar.toggleClass("hidden").animate({
+ width: hidden ? 26 : 210,
+ height: hidden ? $("h1").outerHeight() - 1 : "100%",
+ right: hidden ? 0 : -210
+ }, speed).children(":not(#sidebar-toggle)").animate({
+ opacity: "toggle"
+ }, speed);
+ $("h1").animate({marginRight: hidden ? 26 : 0}, speed);
+
+ $("#sidebar-toggle")
+ .attr("title", hidden ? "Show Sidebar" : "Hide Sidebar");
+ $.futon.storage.set("sidebar", hidden ? "hidden" : "show");
+ };
+ }
+
+ function Storage() {
+ var storage = this;
+ this.decls = {};
+
+ this.declare = function(name, options) {
+ this.decls[name] = $.extend({}, {
+ scope: "window",
+ defaultValue: null,
+ prefix: ""
+ }, options || {});
+ }
+
+ this.declareWithPrefix = function(prefix, decls) {
+ for (var name in decls) {
+ var options = decls[name];
+ options.prefix = prefix;
+ storage.declare(name, options);
+ }
+ }
+
+ this.del = function(name) {
+ lookup(name, function(decl) {
+ handlers[decl.scope].del(decl.prefix + name);
+ });
+ }
+
+ this.get = function(name, defaultValue) {
+ return lookup(name, function(decl) {
+ var value = handlers[decl.scope].get(decl.prefix + name);
+ if (value !== undefined) {
+ return value;
+ }
+ if (defaultValue !== undefined) {
+ return defaultValue;
+ }
+ return decl.defaultValue;
+ });
+ }
+
+ this.set = function(name, value) {
+ lookup(name, function(decl) {
+ if (value == decl.defaultValue) {
+ handlers[decl.scope].del(decl.prefix + name);
+ } else {
+ handlers[decl.scope].set(decl.prefix + name, value);
+ }
+ });
+ }
+
+ function lookup(name, callback) {
+ var decl = storage.decls[name];
+ if (decl === undefined) {
+ return decl;
+ }
+ return callback(decl);
+ }
+
+ // add suffix to cookie names to be able to separate between ports
+ var cookiePrefix = location.port + "_";
+
+ var handlers = {
+
+ "cookie": {
+ get: function(name) {
+ var nameEq = cookiePrefix + name + "=";
+ var parts = document.cookie.split(';');
+ for (var i = 0; i < parts.length; i++) {
+ var part = parts[i].replace(/^\s+/, "");
+ if (part.indexOf(nameEq) == 0) {
+ return unescape(part.substring(nameEq.length, part.length));
+ }
+ }
+ },
+ set: function(name, value) {
+ var date = new Date();
+ date.setTime(date.getTime() + 14*24*60*60*1000); // two weeks
+ document.cookie = cookiePrefix + name + "=" + escape(value) +
+ "; expires=" + date.toGMTString();
+ },
+ del: function(name) {
+ var date = new Date();
+ date.setTime(date.getTime() - 24*60*60*1000); // yesterday
+ document.cookie = cookiePrefix + name + "=" +
+ "; expires=" + date.toGMTString();
+ }
+ },
+
+ "window": {
+ get: function(name) {
+ return JSON.parse(window.name || "{}")[name];
+ },
+ set: function(name, value) {
+ var obj = JSON.parse(window.name || "{}");
+ obj[name] = value || null;
+ window.name = JSON.stringify(obj);
+ },
+ del: function(name) {
+ var obj = JSON.parse(window.name || "{}");
+ delete obj[name];
+ window.name = JSON.stringify(obj);
+ }
+ }
+
+ };
+
+ }
+
+ $.couch.urlPrefix = "..";
+ $.futon = $.futon || {};
+ $.extend($.futon, {
+ navigation: new Navigation(),
+ session : new Session(),
+ storage: new Storage()
+ });
+
+ $.fn.addPlaceholder = function() {
+ if (this[0] && "placeholder" in document.createElement("input")) {
+ return; // found native placeholder support
+ }
+ return this.live('focusin', function() {
+ var input = $(this);
+ if (input.val() === input.attr("placeholder")) {
+ input.removeClass("placeholder").val("");
+ }
+ }).live("focusout", function() {
+ var input = $(this);
+ if (input.val() === "") {
+ input.val(input.attr("placeholder")).addClass("placeholder");
+ }
+ }).trigger("focusout");
+ }
+
+ $.fn.enableTabInsertion = function(chars) {
+ chars = chars || "\t";
+ var width = chars.length;
+ return this.keydown(function(evt) {
+ if (evt.keyCode == 9) {
+ var v = this.value;
+ var start = this.selectionStart;
+ var scrollTop = this.scrollTop;
+ if (start !== undefined) {
+ this.value = v.slice(0, start) + chars + v.slice(start);
+ this.selectionStart = this.selectionEnd = start + width;
+ } else {
+ document.selection.createRange().text = chars;
+ this.caretPos += width;
+ }
+ return false;
+ }
+ });
+ }
+
+ $(document)
+ .ajaxStart(function() { $(this.body).addClass("loading"); })
+ .ajaxStop(function() { $(this.body).removeClass("loading"); });
+
+ $.futon.storage.declare("sidebar", {scope: "cookie", defaultValue: "show"});
+ $.futon.storage.declare("recent", {scope: "cookie", defaultValue: ""});
+
+ $(function() {
+ document.title = "Apache CouchDB - Futon: " + document.title;
+ if ($.futon.storage.get("sidebar") == "hidden") {
+ // doing this as early as possible prevents flickering
+ $(document.body).addClass("fullwidth");
+ }
+ $("input[placeholder]").addPlaceholder();
+
+ $.get("_sidebar.html", function(resp) {
+ $("#wrap").append(resp)
+ .find("#sidebar-toggle").click(function(e) {
+ $.futon.navigation.toggle(e.shiftKey ? 2500 : 500);
+ return false;
+ });
+ if ($.futon.storage.get("sidebar") == "hidden") {
+ $.futon.navigation.toggle(0);
+ }
+
+ $.futon.navigation.updateDatabases();
+ $.futon.navigation.updateSelection();
+ $.futon.navigation.ready();
+ $.futon.session.setupSidebar();
+ $.futon.session.sidebar();
+
+ $.couch.info({
+ success: function(info, status) {
+ $("#version").text(info.version);
+ }
+ });
+ });
+ });
+
+})(jQuery);