couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From gar...@apache.org
Subject [1/2] fauxton commit: updated refs/heads/master to ddef3d5
Date Mon, 02 Feb 2015 07:32:12 GMT
Repository: couchdb-fauxton
Updated Branches:
  refs/heads/master 9f26ac1e2 -> ddef3d54c


Initial add CORS to Fauxton


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/a9636bdc
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/a9636bdc
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/a9636bdc

Branch: refs/heads/master
Commit: a9636bdcdd7ccabb868c678d9be0ac339df282e0
Parents: 9f26ac1
Author: Christian Hogan <github@infliction.org>
Authored: Fri Nov 28 13:19:13 2014 -0500
Committer: Garren Smith <garren.smith@gmail.com>
Committed: Mon Feb 2 09:30:46 2015 +0200

----------------------------------------------------------------------
 app/addons/config/assets/less/config.less       |   4 +
 app/addons/config/routes.js                     |  33 +-
 app/addons/config/templates/dashboard.html      |   2 +-
 app/addons/config/templates/sidebartabs.html    |  10 +
 app/addons/config/views.js                      |  24 ++
 app/addons/cors/assets/less/cors.less           | 126 +++++++
 app/addons/cors/base.js                         |  24 ++
 app/addons/cors/resources.js                    |  64 ++++
 app/addons/cors/routes.js                       |  21 ++
 app/addons/cors/templates/cors.html             |  50 +++
 .../cors/templates/origin_domain_row.html       |  33 ++
 .../cors/templates/origin_domain_table.html     |  17 +
 app/addons/cors/views.js                        | 337 +++++++++++++++++++
 settings.json.default                           |   1 +
 14 files changed, 741 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/config/assets/less/config.less
----------------------------------------------------------------------
diff --git a/app/addons/config/assets/less/config.less b/app/addons/config/assets/less/config.less
index 6cd0ed2..fd496c6 100644
--- a/app/addons/config/assets/less/config.less
+++ b/app/addons/config/assets/less/config.less
@@ -41,6 +41,10 @@
 }
 
 table.config {
+  thead th {
+    border-left: none;
+    border-bottom: 2px solid #999;
+  }
   tr {
     th, td {
       vertical-align: middle;

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/config/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/config/routes.js b/app/addons/config/routes.js
index 62fd9b1..32dc4cc 100644
--- a/app/addons/config/routes.js
+++ b/app/addons/config/routes.js
@@ -14,16 +14,33 @@ define([
   'app',
   'api',
   'addons/config/resources',
-  'addons/config/views'
+  'addons/config/views',
+  'addons/cors/views'
 ],
 
-function(app, FauxtonAPI, Config, Views) {
+function(app, FauxtonAPI, Config, Views, CORS) {
 
   var ConfigRouteObject = FauxtonAPI.RouteObject.extend({
-    layout: 'one_pane',
+    layout: 'with_tabs_sidebar',
 
     initialize: function () {
       this.configs = new Config.Collection();
+      this.cors = new CORS.config();
+      
+      this.sidebar = this.setView("#sidebar-content", new Views.Tabs({
+        sidebarItems: [
+          {
+            title: 'Main config',
+            typeSelect: 'main',
+            link: '_config'
+          },
+          {
+            title: 'CORS',
+            typeSelect: 'cors',
+            link: '_config/cors'
+          }
+        ]
+      }));
     },
 
     roles: ['_admin'],
@@ -38,12 +55,20 @@ function(app, FauxtonAPI, Config, Views) {
     },
 
     routes: {
-      '_config': 'config'
+      '_config': 'config',
+      '_config/cors':'configCORS'
     },
 
     config: function () {
       this.newSection = this.setView('#right-header', new Views.ConfigHeader({ collection:
this.configs }));
       this.setView('#dashboard-content', new Views.Table({ collection: this.configs }));
+      this.sidebar.setSelectedTab("main");
+    },
+    
+    configCORS: function() {
+      this.removeView('#right-header');
+      this.newSection = this.setView('#dashboard-content', new CORS.Views.CORSMain({ model:
this.cors }));
+      this.sidebar.setSelectedTab("cors");
     },
 
     establish: function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/config/templates/dashboard.html
----------------------------------------------------------------------
diff --git a/app/addons/config/templates/dashboard.html b/app/addons/config/templates/dashboard.html
index f7fae00..0af857d 100644
--- a/app/addons/config/templates/dashboard.html
+++ b/app/addons/config/templates/dashboard.html
@@ -14,7 +14,7 @@ the License.
 
 <table class="config table table-striped table-bordered">
   <thead>
-    <th id="config-section" width="20%">Section</th>
+    <th id="config-section" width="22%">Section</th>
     <th id="config-option" width="20%">Option</th>
     <th id="config-value">Value</th>
     <th id="config-trash"></th>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/config/templates/sidebartabs.html
----------------------------------------------------------------------
diff --git a/app/addons/config/templates/sidebartabs.html b/app/addons/config/templates/sidebartabs.html
new file mode 100644
index 0000000..b48b0ae
--- /dev/null
+++ b/app/addons/config/templates/sidebartabs.html
@@ -0,0 +1,10 @@
+<ul class="nav nav-list">
+  <% _.each(sidebarItems, function (item) { %>
+    <li>
+    <a data-type-select="<%- item.typeSelect %>" href="#<%- item.link %>">
+      <span class="<%- item.icon %>"></span>
+      <%- item.title %>
+    </a>
+    </li>
+  <% }); %>
+</ul>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/config/views.js
----------------------------------------------------------------------
diff --git a/app/addons/config/views.js b/app/addons/config/views.js
index 034205a..1ccdc3e 100644
--- a/app/addons/config/views.js
+++ b/app/addons/config/views.js
@@ -243,6 +243,30 @@ function(app, FauxtonAPI, Config, Components) {
       });
     }
   });
+  
+  Views.Tabs = FauxtonAPI.View.extend({
+    className: "sidenav",
+    tagName: "nav",
+    template: 'addons/config/templates/sidebartabs',
+    initialize: function (options) {
+      this.sidebarItems = options.sidebarItems;
+    },
+
+    setSelectedTab: function (selectedTab) {
+      this.selectedTab = selectedTab;
+      this.$('li').removeClass('active');
+      this.$('a[data-type-select="'+this.selectedTab+'"]').parent("li").addClass('active');
+    },
+    afterRender: function(){
+      this.setSelectedTab(this.selectedTab);
+    },
+
+    serialize: function () {
+      return {
+        sidebarItems: this.sidebarItems
+      };
+    }
+  });
 
   return Views;
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/assets/less/cors.less
----------------------------------------------------------------------
diff --git a/app/addons/cors/assets/less/cors.less b/app/addons/cors/assets/less/cors.less
new file mode 100644
index 0000000..4e06032
--- /dev/null
+++ b/app/addons/cors/assets/less/cors.less
@@ -0,0 +1,126 @@
+/*  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.
+ */
+
+/* =cors
+   ---------------------------------------------------------------------- */
+@import "../../../../../assets/less/bootstrap/variables.less";
+@import "../../../../../assets/less/variables.less";
+@import "../../../../../assets/less/bootstrap/mixins.less";
+
+#sidebar-content .nav-list li a span {
+  display: none;
+}
+
+#cors-header {
+  margin: 18px 30px 0 30px;
+}
+
+#corsForm {
+  margin: 0;
+
+  .checkbox {
+    font-size: 16px;
+
+    input[type='checkbox'] {
+      margin-top: 4px;
+    }
+  }
+  .radio {
+    font-size: 16px;
+
+    input[type='radio'] {
+      margin-top: 4px;
+    }
+  }
+
+  .cors-enable {
+    padding: 10px 30px 18px 30px;
+    border-bottom: 1px solid #ccc;
+  }
+  #origin-domains-container {
+    display: none;
+    
+    .new-origin-domain {
+      width: 100%;
+      border-radius: 6px;
+    }
+  }
+  #collapsing-container {
+    border-top: 1px solid #fff;
+    border-bottom: 1px solid #ccc;
+    padding: 18px 30px;
+    display: none;
+  }
+  .origin-domains {
+    margin: 0;
+    padding: 18px 0px;
+    
+    p {
+      line-height: 36px;
+    }
+    .controls {
+      margin-top: 18px;
+    }
+  }
+  .localhost-tip {
+    padding: 18px 30px;
+    border-top: 1px solid #fff;
+    border-bottom: 1px solid #ccc;
+  }
+  .form-actions {
+    padding: 18px 30px;
+    margin-top: 0;
+    border-top: 1px solid #fff;
+  }
+}
+
+#origin-domain-table {
+  td {
+    padding: 8px 2px;
+  }
+  span {
+    cursor: pointer;
+    color: #E33F3B;
+    display: inline-block;
+    padding-top: 9px;
+  }
+
+  .edit-domain-section {
+    position: relative;
+    margin-right: 20px;
+
+    .field-wrapper {
+      margin-right: 78px;
+    }
+    input {
+      width: 100%;
+      padding: 9px;
+      margin: 0 0 0 4px;
+    }
+  }
+  .url-display {
+    padding: 10px;
+  }
+
+  .hide {
+    display: none;
+  }
+
+  .update-domain-btn {
+    position: absolute;
+    right: -2px;
+    top: 0;
+    padding: 9px;
+    border-radius: 0 6px 6px 0;
+  }
+}

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/base.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/base.js b/app/addons/cors/base.js
new file mode 100644
index 0000000..b5824e3
--- /dev/null
+++ b/app/addons/cors/base.js
@@ -0,0 +1,24 @@
+// 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.
+
+define([
+  "app",
+  "api",
+  "addons/cors/routes"
+],
+
+function (app, FauxtonAPI, CORS) {
+
+  CORS.initialize = function() {};
+
+  return CORS;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/resources.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/resources.js b/app/addons/cors/resources.js
new file mode 100644
index 0000000..bd3809e
--- /dev/null
+++ b/app/addons/cors/resources.js
@@ -0,0 +1,64 @@
+// 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.
+
+define([
+  "app",
+  "api"
+],
+
+function (app, FauxtonAPI) {  
+  var CORS = FauxtonAPI.addon();
+
+
+  CORS.config = FauxtonAPI.Model.extend({
+    url: function() {
+      return app.host+"/_config/cors";
+    }
+  });
+  
+  CORS.ConfigModel = Backbone.Model.extend({
+    documentation: "cors",
+    
+    url: function () {
+      return app.host + '/_config/' + encodeURIComponent(this.get("section")) + '/' + encodeURIComponent(this.get("attribute"));
+    },
+    
+    isNew: function () { return false; },
+    
+    sync: function (method, model, options) {
+
+      var params = {
+        url: model.url(),
+        contentType: 'application/json',
+        dataType: 'json',
+        data: JSON.stringify(model.get('value'))
+      };
+
+      if (method === 'delete') {
+        params.type = 'DELETE';
+      } else {
+        params.type = 'PUT';
+      }
+
+      return $.ajax(params);
+    }
+  
+  });
+  
+    // simple helper function to validate the user entered a valid domain starting with http(s)
and
+  // not including any subfolder
+  CORS.validateCORSDomain = function (str) {
+    return (/^https?:\/\/[a-zA-Z0-9\-]+\.[a-zA-Z0-9\-\.]+$/).test(str);
+  };
+
+  return CORS;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/routes.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/routes.js b/app/addons/cors/routes.js
new file mode 100644
index 0000000..017211b
--- /dev/null
+++ b/app/addons/cors/routes.js
@@ -0,0 +1,21 @@
+// 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.
+
+define([
+  'app',
+  'api',
+  'addons/cors/views'
+],
+
+function (app, FauxtonAPI, CORS) {
+  return CORS;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/templates/cors.html
----------------------------------------------------------------------
diff --git a/app/addons/cors/templates/cors.html b/app/addons/cors/templates/cors.html
new file mode 100644
index 0000000..8db6a60
--- /dev/null
+++ b/app/addons/cors/templates/cors.html
@@ -0,0 +1,50 @@
+<!--
+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.
+-->
+
+<header id="cors-header">
+  <p>Cross-Origin Resource Sharing (CORS) lets you connect to remote servers directly
from the browser, so you can host browser-based apps on static pages and talk directly with
CouchDB to load your data.</p>
+</header>
+
+<form id="corsForm">
+
+  <div class="cors-enable">
+    <label class="checkbox">
+      <input type="checkbox" class="js-enable-cors" name="enable_cors" <% if  (typeof
enableCors !== 'undefined' && enableCors === 'true') { %> checked="checked" <%
} %>> Enable CORS
+    </label>
+  </div>
+  
+  <div id="collapsing-container">
+    <p><strong>Origin Domains</strong></p>
+    
+    <p>Databases will accept requests from these domains:</p>
+    
+    <label class="checkbox"><input type="checkbox" class="js-all-origin-domains"
name="all_origin_domains"> All origin domains ( * )</label></li>
+        
+    <label class="checkbox"><input type="checkbox" class="js-restrict-origin-domains"
name="restrict_origin_domains"> Restrict to specific origin domains</label>
+      
+    <div id="origin-domains-container">
+      <div class="origin-domains"></div>
+      <input type="text" class="new-origin-domain" name="new_origin_domain" value="" placeholder="e.g.,
https://site.com" />
+    </div>
+    
+    </div>
+    
+  </div>
+
+  <div class="form-actions">
+    <input class="btn btn-success" type="submit" value="Save" />
+  </div>
+
+</form>
+

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/templates/origin_domain_row.html
----------------------------------------------------------------------
diff --git a/app/addons/cors/templates/origin_domain_row.html b/app/addons/cors/templates/origin_domain_row.html
new file mode 100644
index 0000000..19f6954
--- /dev/null
+++ b/app/addons/cors/templates/origin_domain_row.html
@@ -0,0 +1,33 @@
+<!--
+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.
+-->
+
+<td>
+  <div class="js-url url-display"><%-url%></div>
+
+  <div class="js-edit-domain edit-domain-section hide">
+    <div class="field-wrapper">
+      <input type="text" value="<%-url%>" />
+    </div>
+    <a class="js-save-domain btn update-domain-btn">
+      <i class="fonticon-save"></i>
+      Update
+    </a>
+  </div>
+</td>
+<td width="30">
+  <span class="js-edit fonticon-pencil" title="Click to edit"></span>
+</td>
+<td width="30">
+  <span class="js-delete fonticon-trash" title="Click to delete"></span>
+</td>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/templates/origin_domain_table.html
----------------------------------------------------------------------
diff --git a/app/addons/cors/templates/origin_domain_table.html b/app/addons/cors/templates/origin_domain_table.html
new file mode 100644
index 0000000..7192bea
--- /dev/null
+++ b/app/addons/cors/templates/origin_domain_table.html
@@ -0,0 +1,17 @@
+<!--
+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.
+-->
+
+<table id="origin-domain-table" class="table table-striped">
+  <tbody></tbody>
+</table>

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/app/addons/cors/views.js
----------------------------------------------------------------------
diff --git a/app/addons/cors/views.js b/app/addons/cors/views.js
new file mode 100644
index 0000000..c390d5a
--- /dev/null
+++ b/app/addons/cors/views.js
@@ -0,0 +1,337 @@
+// 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.
+
+define([
+  "app",
+  "api",
+  "addons/cors/resources"
+],
+
+
+function (app, FauxtonAPI, CORS) {
+  var Views= {};
+  
+  Views.CORSMain = FauxtonAPI.View.extend({
+    className: 'cors-page',
+    template: 'addons/cors/templates/cors',
+    events: {
+      'submit form#corsForm': 'submit',
+      'click .js-enable-cors': 'corsClick',
+      'click .js-restrict-origin-domains': 'restrictOrigins',
+      'click .js-all-origin-domains': 'allOrigins'
+    },
+    
+    initialize: function () {
+      this.originDomainTable = this.setView('.origin-domains', new Views.OriginDomainTable({
+        model: this.model
+      }));
+    },
+    
+    serialize: function () {
+      return {
+        enableCors: this.model.get('credentials')    
+      };
+    },
+    
+    establish: function(){
+      return [this.model.fetch()];
+    },
+    
+    afterRender: function () {        
+      var corsEnabled = this.$('.js-enable-cors').is(':checked');
+      this.$('#collapsing-container').toggle(corsEnabled);
+      this.setupOrigins();
+    },
+    
+    corsClick: function (e) {
+      var isChecked = this.$(e.target).prop('checked');
+      this.$('#collapsing-container').toggle(isChecked);
+      this.setupOrigins();
+    },
+    
+    
+    setupOrigins: function() {
+      var storedOrigins = this.model.get('origins');
+      if (storedOrigins && storedOrigins != '*') {
+        this.restrictOrigins();
+      } else {
+        this.allOrigins();
+      }
+    },
+    
+    allOrigins: function() {
+      this.$('.js-all-origin-domains').prop('checked', true);
+      this.$('.js-restrict-origin-domains').prop('checked', false);
+      this.$('#origin-domains-container').hide();
+    },
+
+    restrictOrigins: function() {
+      this.$('.js-restrict-origin-domains').prop('checked', true);
+      this.$('.js-all-origin-domains').prop('checked', false);
+      this.$('#origin-domains-container').show();
+    },
+    
+    formToJSON: function(formSelector){
+      var formObject = $(formSelector).serializeArray(),
+        formJSON={};
+      _.map(formObject, function(field){
+        formJSON[field.name]=field.value;
+      });
+      return formJSON;
+    },
+    
+    submit: function(e){
+      e.preventDefault();      
+      var data = this.formToJSON(e.currentTarget);
+
+      if (data.enable_cors === 'on') {
+
+        // CORS checked, save data  
+        if (data.restrict_origin_domains === 'on') {
+          var storedOrigins = this.model.get('origins').split(',');
+          var newDomain = $.trim(data.new_origin_domain);
+	
+          // if a new domain has been entered, check it's valid
+          if (!_.isEmpty(newDomain) && !CORS.validateCORSDomain(newDomain)) {
+            FauxtonAPI.addNotification({
+              msg: 'Please enter a valid domain, starting with http/https and only containing
the domain (not a subfolder).',
+              type: 'error',
+              clear: true
+            });
+            return;
+          }
+          
+          // check that the user has entered at least one new origin domain
+          if (storedOrigins && storedOrigins.length > 0 && storedOrigins
!== '*') {
+            this.originData = storedOrigins.concat(newDomain).toString();            
+          } else {
+            if (_.isEmpty(newDomain)) {
+              FauxtonAPI.addNotification({
+                msg: 'Please enter a new origin domain.',
+                type: 'error',
+                clear: true
+              });
+              this.$('.new-origin-domain').focus();
+              return;
+            }
+            this.originData = data.new_origin_domain;
+          }
+          
+        } else {
+          this.originData = "*";
+        }
+        
+          
+        var enableOption = new CORS.ConfigModel({
+          section: 'httpd',
+          attribute: 'enable_cors',
+          value: 'true'
+        });
+        
+        var enableCreds = new CORS.ConfigModel({
+          section: 'cors',
+          attribute: 'credentials',
+          value: 'true'
+        });
+        
+        var allowOrigins = new CORS.ConfigModel({
+          section: 'cors',
+          attribute: 'origins',
+          value: this.originData
+        });
+
+        enableOption.save().then(function (response) {
+          var notification = FauxtonAPI.addNotification({
+            msg: 'Your settings have been saved.',
+            type: 'success',
+            clear: true
+          });
+        },
+        function (response, errorCode, errorMsg) {
+          var notification = FauxtonAPI.addNotification({
+            msg: 'Sorry! There was an error. Code ' + errorCode  + '.',
+            type: 'error',
+            clear: true
+          });
+        });
+        
+        enableCreds.save();
+        allowOrigins.save();
+        this.$('.new-origin-domain').val('');
+      
+      } else {
+          
+        // Disable CORS
+        var disableOption = new CORS.ConfigModel({
+          section: 'httpd',
+          attribute: 'enable_cors',
+          value: 'false'
+        });
+        
+        var disableCreds = new CORS.ConfigModel({
+          section: 'cors',
+          attribute: 'credentials',
+          value: 'false'
+        });
+        
+        var disableOrigins = new CORS.ConfigModel({
+          section: 'cors',
+          attribute: 'origins',
+          value: ''
+        });
+        
+        disableOption.save().then(function (response) {
+          var notification = FauxtonAPI.addNotification({
+            msg: 'Your settings have been saved.',
+            type: 'success',
+            clear: true
+          });
+        },
+        function (response, errorCode, errorMsg) {
+          var notification = FauxtonAPI.addNotification({
+            msg: 'Sorry! There was an error. Code ' + errorCode  + '.',
+            type: 'error',
+            clear: true
+          });
+        });
+          
+        disableCreds.save();
+        disableOrigins.save();
+      }
+    }
+  });
+  
+  Views.OriginDomainTable = FauxtonAPI.View.extend({
+    template: 'addons/cors/templates/origin_domain_table',
+
+    initialize: function () {
+      // listen for any server-side changes to the object (i.e. saves/deletes). Only then,
re-render the table
+      this.listenTo(this.model, 'sync', this.render);
+    },
+
+    beforeRender: function () {
+      var origins = this.model.get('origins');
+
+      // if the stored origins are set to '*' or nothing's defined, show nothing
+      if (_.isEmpty(origins) || origins === '*') {
+        return;
+      }
+      this.showRows();
+    },
+
+    showRows: function () {
+        var originsArray = this.model.get('origins').split(',');
+      _.each(originsArray, function (url, index) {
+        this.insertView('#origin-domain-table tbody', new Views.OriginDomainRow({
+          model: this.model,
+          index: index
+        }));
+      }, this);
+    }
+  });
+
+
+  // this gets passed the entire model so it can manipulate it directly (add/update the row)
+  Views.OriginDomainRow = FauxtonAPI.View.extend({
+    template: 'addons/cors/templates/origin_domain_row',
+    tagName: 'tr',
+
+    events: {
+      'click .js-edit': 'onEditDomain',
+      'click .js-cancel-edit': 'onCancelEditDomain',
+      'click .js-delete': 'onDeleteDomain',
+      'click .js-save-domain': 'onSaveDomain'
+    },
+
+    serialize: function () {
+      return {
+        url: this.model.get('origins').split(',')[this.index]
+      };
+    },
+
+    onEditDomain: function () {
+
+      // show the editable field & save button
+      this.$('.js-url').addClass('hide');
+      this.$('.js-edit-domain').removeClass('hide');
+
+      // change the edit icon to a cancel icon
+      this.$('.js-edit').removeClass('js-edit fonticon-pencil')
+        .addClass('js-cancel-edit fonticon-cancel').attr("title", "Click to cancel");
+      this.$('.js-edit-domain input').select();
+    },
+
+    onCancelEditDomain: function () {
+      this.$('.js-url').removeClass('hide');
+      this.$('.js-edit-domain').addClass('hide');
+      this.$('.js-cancel-edit').removeClass('js-cancel-edit fonticon-cancel')
+        .addClass('js-edit fonticon-pencil').attr("title", "Click to edit");
+    },
+
+    onSaveDomain: function () {
+      var newDomain = this.$('.js-edit-domain input').val();
+
+      if (!CORS.validateCORSDomain(newDomain)) {
+        FauxtonAPI.addNotification({
+          msg: "Please enter a valid domain, starting with http/https and only containing
the domain (not a subfolder).",
+          type: "error",
+          clear: true
+        });
+        return;
+      }
+
+      var domains = this.model.get('origins').split(',');
+      domains[this.index] = newDomain;
+      this.saveOrigins(domains);
+    },
+
+    // remove the domain from the list
+    onDeleteDomain: function () {
+
+      // remove the domain from the list. Anyone monitoring the object will hear that it's
changed (e.g.
+      // the main table, which will know to re-render)
+      var domains = this.model.get('origins').split(',');
+      domains.splice(this.index, 1);
+
+      this.saveOrigins(domains);
+    },
+
+    saveOrigins: function (origins) {
+      var originDomains = origins.toString();
+      
+      var allowOrigins = new CORS.ConfigModel({
+        section: 'cors',
+        attribute: 'origins',
+        value: originDomains
+      });
+      
+      allowOrigins.save().then(function (response) {
+        var notification = FauxtonAPI.addNotification({
+          msg: 'Your origin domains have been updated.',
+          type: 'success',
+          clear: true
+        });
+      },
+      function (response, errorCode, errorMsg) {
+        var notification = FauxtonAPI.addNotification({
+          msg: 'Something went wrong.',
+          type: 'error',
+          clear: true
+        });
+      });
+    }
+  });
+  
+  CORS.Views = Views;
+
+  return CORS;
+});

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/a9636bdc/settings.json.default
----------------------------------------------------------------------
diff --git a/settings.json.default b/settings.json.default
index 8e88c0e..1e6aa50 100644
--- a/settings.json.default
+++ b/settings.json.default
@@ -6,6 +6,7 @@
   { "name": "activetasks" },
   { "name": "config" },
   { "name": "replication" },
+  { "name": "cors" },
   { "name": "plugins" },
   { "name": "permissions" },
   { "name": "compaction" },


Mime
View raw message