[Testbot] Plone 5.0 - Python 2.7 - Build # 1886 - Fixed! - 0 failure(s)

jenkins at plone.org jenkins at plone.org
Sat Mar 8 13:08:37 UTC 2014


-------------------------------------------------------------------------------
Plone 5.0 - Python 2.7 - Build # 1886 - Fixed!
-------------------------------------------------------------------------------

http://jenkins.plone.org/job/plone-5.0-python-2.7/1886/


-------------------------------------------------------------------------------
CHANGES
-------------------------------------------------------------------------------

Repository: mockup
Branch: refs/heads/master
Date: 2014-03-07T12:13:15-06:00
Author: Nathan Van Gheem (vangheem) <vangheem at gmail.com>
Commit: https://github.com/plone/mockup/commit/7a38cd1be6720713664b02f9d085f0f9de0da912

provide folder context actions

Files changed:
A js/patterns/structure/templates/actionmenu.xml
A js/patterns/structure/views/actionmenu.js
M js/patterns/structure/pattern.js
M js/patterns/structure/templates/table.xml
M js/patterns/structure/templates/tablerow.xml
M js/patterns/structure/views/table.js
M js/patterns/structure/views/tablerow.js
M less/pattern.structure.less
M tests/fakeserver.js
M tests/pattern-structure-test.js

diff --git a/js/patterns/structure/pattern.js b/js/patterns/structure/pattern.js
index f09f758..a6cf4c8 100644
--- a/js/patterns/structure/pattern.js
+++ b/js/patterns/structure/pattern.js
@@ -22,7 +22,7 @@
  *                             tagsVocabularyUrl:/select2-test.json;
  *                             usersVocabularyUrl:/tests/json/users.json;
  *                             indexOptionsUrl:/tests/json/queryStringCriteria.json;
- *                             contextInfoUrl:/tests/json/contextInfo.json;"></div>
+ *                             contextInfoUrl:{path}/context-info;"></div>
  *
  * License:
  *    Copyright (C) 2010 Plone Foundation
diff --git a/js/patterns/structure/templates/actionmenu.xml b/js/patterns/structure/templates/actionmenu.xml
new file mode 100644
index 0000000..2db76a0
--- /dev/null
+++ b/js/patterns/structure/templates/actionmenu.xml
@@ -0,0 +1,25 @@
+<a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" href="#">
+  <span class="glyphicon glyphicon-cog"></i>
+  <span class="caret"></span>
+</a>
+<ul class="dropdown-menu">
+  <% if(header) { %>
+    <li class="dropdown-header"><%- header %></li>
+    <li class="divider"></li>
+  <% } %>
+  <li class="cutItem"><a href="#">Cut</a></li>
+  <li class="copyItem"><a href="#">Copy</a></li>
+  <% if(pasteAllowed && attributes.is_folderish){ %>
+    <li class="pasteItem"><a href="#">Paste</a></li>
+  <% } %>
+  <% if(!inQueryMode && canMove){ %>
+    <li class="move-top"><a href="#">Move to top of folder</a></li>
+    <li class="move-bottom"><a href="#">Move to bottom of folder</a></li>
+  <% } %>
+  <% if(!attributes.is_folderish && canSetDefaultPage){ %>
+    <li class="set-default-page"><a href="#">Set as default page</a></li>
+  <% } %>
+  <li class="openItem"><a href="#">Open</a></li>
+  <li class="editItem"><a href="#">Edit</a></li>
+</ul>
+
diff --git a/js/patterns/structure/templates/table.xml b/js/patterns/structure/templates/table.xml
index 64ca80a..429d67b 100644
--- a/js/patterns/structure/templates/table.xml
+++ b/js/patterns/structure/templates/table.xml
@@ -3,19 +3,30 @@
 </div>
 <table class="table table-striped table-bordered">
   <thead>
-    <tr class="breadcrumbs">
-        <td colspan="<%= activeColumns.length + 3 %>">
+    <tr class="breadcrumbs-container">
+      <td colspan="<%= activeColumns.length + 3 %>">
+        <% if(pathParts.length > 0) { %>
+          <div class="input-group context-buttons" style="display:none">
+            <span class="input-group-addon">
+              <input type="checkbox" />
+            </span>
+            <div class="input-group-btn">
+            </div>
+          </div>
+        <% } %>
+        <div class="breadcrumbs">
           <a href="#" data-path="/">
-              <span class="icon icon-home"></span> /
+            <span class="glyphicon glyphicon-home"></span> /
           </a>
-        <% _.each(pathParts, function(part, idx, list){
-          if(part){
-            if(idx > 0){ %>
-              /
-            <% } %>
-            <a href="#" class="crumb" data-path="<%- part %>"><%- part %></a>
-          <% }
-        }); %>
+          <% _.each(pathParts, function(part, idx, list){
+            if(part){
+              if(idx > 0){ %>
+                /
+              <% } %>
+              <a href="#" class="crumb" data-path="<%- part %>"><%- part %></a>
+            <% }
+          }); %>
+        </div>
       </td>
     </tr>
     <tr>
diff --git a/js/patterns/structure/templates/tablerow.xml b/js/patterns/structure/templates/tablerow.xml
index 9cd8bab..27406d7 100644
--- a/js/patterns/structure/templates/tablerow.xml
+++ b/js/patterns/structure/templates/tablerow.xml
@@ -18,27 +18,5 @@
     <td class="<%- column %>"><%- attributes[column] %></td>
   <% } %>
 <% }); %>
-<td>
-  <div class="btn-group">
-    <a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" href="#">
-      <span class="glyphicon glyphicon-cog"></i>
-      <span class="caret"></span>
-    </a>
-    <ul class="dropdown-menu">
-      <li class="cutItem"><a href="#">Cut</a></li>
-      <li class="copyItem"><a href="#">Copy</a></li>
-      <% if(pasteAllowed && attributes.is_folderish){ %>
-        <li class="pasteItem"><a href="#">Paste</a></li>
-      <% } %>
-      <% if(!inQueryMode){ %>
-        <li class="move-top"><a href="#">Move to top of folder</a></li>
-        <li class="move-bottom"><a href="#">Move to bottom of folder</a></li>
-      <% } %>
-      <% if(!attributes.is_folderish && canSetDefaultPage){ %>
-        <li class="set-default-page"><a href="#">Set as default page</a></li>
-      <% } %>
-      <li class="openItem"><a href="#">Open</a></li>
-      <li class="editItem"><a href="#">Edit</a></li>
-    </ul>
-  </div>
+<td class="actionmenu-container">
 </td>
diff --git a/js/patterns/structure/views/actionmenu.js b/js/patterns/structure/views/actionmenu.js
new file mode 100644
index 0000000..3965ab0
--- /dev/null
+++ b/js/patterns/structure/views/actionmenu.js
@@ -0,0 +1,171 @@
+// Author: Nathan Van Gheem
+// Contact: nathan at vangheem.us
+// Version: 1.0
+//
+// Description:
+//
+// License:
+//
+// Copyright (C) 2010 Plone Foundation
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+
+/* global alert:true */
+
+define([
+  'jquery',
+  'underscore',
+  'backbone',
+  'js/ui/views/base',
+  'mockup-utils',
+  'text!js/patterns/structure/templates/actionmenu.xml',
+  'bootstrap-dropdown'
+], function($, _, Backbone, BaseView, utils, ActionMenuTemplate) {
+  'use strict';
+
+  var ActionMenu = BaseView.extend({
+    className: 'btn-group actionmenu',
+    template: _.template(ActionMenuTemplate),
+    events: {
+      'click .cutItem a': 'cutClicked',
+      'click .copyItem a': 'copyClicked',
+      'click .pasteItem a': 'pasteClicked',
+      'click .move-top a': 'moveTopClicked',
+      'click .move-bottom a': 'moveBottomClicked',
+      'click .set-default-page a': 'setDefaultPageClicked',
+      'click .openItem a': 'openClicked',
+      'click .editItem a': 'editClicked'
+    },
+    initialize: function(options) {
+      this.options = options;
+      this.app = options.app;
+      this.model = options.model;
+      this.selectedCollection = this.app.selectedCollection;
+      if (options.canMove === false){
+        this.canMove = false;
+      }else {
+        this.canMove = true;
+      }
+    },
+    cutClicked: function(e) {
+      e.preventDefault();
+      this.cutCopyClicked('cut');
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    copyClicked: function(e) {
+      e.preventDefault();
+      this.cutCopyClicked('copy');
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    cutCopyClicked: function(operation) {
+      var self = this;
+      self.app.pasteOperation = operation;
+
+      self.app.pasteSelection = new Backbone.Collection();
+      self.app.pasteSelection.add(this.model);
+      self.app.setStatus(operation + ' 1 item');
+      self.app.pasteAllowed = true;
+      self.app.buttons.primary.get('paste').enable();
+    },
+    pasteClicked: function(e) {
+      e.preventDefault();
+      this.app.pasteEvent(this.app.buttons.primary.get('paste'), e, {
+        folder: this.model.attributes.path
+      });
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    moveTopClicked: function(e) {
+      e.preventDefault();
+      this.app.moveItem(this.model.attributes.id, 'top');
+    },
+    moveBottomClicked: function(e) {
+      e.preventDefault();
+      this.app.moveItem(this.model.attributes.id, 'bottom');
+    },
+    setDefaultPageClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      $.ajax({
+        url: self.app.getAjaxUrl(self.app.setDefaultPageUrl),
+        type: 'POST',
+        data: {
+          '_authenticator': $('[name="_authenticator"]').val(),
+          'id': this.$active.attr('data-id')
+        },
+        success: function(data) {
+          self.app.ajaxSuccessResponse.apply(self.app, [data]);
+        },
+        error: function(data) {
+          self.app.ajaxErrorResponse.apply(self.app, [data]);
+        }
+      });
+    },
+    getSelectedBaseUrl: function() {
+      var self = this;
+      return self.model.attributes.getURL;
+    },
+    getWindow: function() {
+      var win = window;
+      if (win.parent !== window) {
+        win = win.parent;
+      }
+      return win;
+    },
+    openUrl: function(url) {
+      var self = this;
+      var win = self.getWindow();
+      var keyEvent = this.app.keyEvent;
+      if (keyEvent && keyEvent.ctrlKey) {
+        win.open(url);
+      } else {
+        win.location = url;
+      }
+    },
+    openClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      self.openUrl(self.getSelectedBaseUrl() + '/view');
+    },
+    editClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      self.openUrl(self.getSelectedBaseUrl() + '/edit');
+    },
+    render: function() {
+      var self = this;
+      self.$el.empty();
+
+      var data = this.model.toJSON();
+      data.attributes = self.model.attributes;
+      data.pasteAllowed = self.app.pasteAllowed;
+      data.canSetDefaultPage = self.app.setDefaultPageUrl;
+      data.inQueryMode = self.app.inQueryMode();
+      data.header = self.options.header;
+      data.canMove = self.canMove;
+
+      self.$el.html(self.template(data));
+
+      self.$dropdown = self.$('.dropdown-toggle');
+      self.$dropdown.dropdown();
+
+      if (self.options.className){
+        self.$el.addClass(self.options.className);
+      }
+      return this;
+    }
+  });
+
+  return ActionMenu;
+});
diff --git a/js/patterns/structure/views/table.js b/js/patterns/structure/views/table.js
index 40c45f6..99bf7ff 100644
--- a/js/patterns/structure/views/table.js
+++ b/js/patterns/structure/views/table.js
@@ -31,9 +31,11 @@ define([
   'text!js/patterns/structure/templates/table.xml',
   'js/ui/views/base',
   'mockup-patterns-sortable',
-  'mockup-patterns-moment'
+  'mockup-patterns-moment',
+  'js/patterns/structure/models/result',
+  'js/patterns/structure/views/actionmenu'
 ], function($, _, Backbone, TableRowView, TableTemplate, BaseView, Sortable,
-            Moment) {
+            Moment, Result, ActionMenu) {
   'use strict';
 
   var TableView = BaseView.extend({
@@ -49,37 +51,67 @@ define([
       self.listenTo(self.selectedCollection, 'reset', self.render);
       self.collection.pager();
       self.subsetIds = [];
+      self.contextInfo = self.folderModel = self.folderMenu = null;
 
       self.app.on('context-info-loaded', function(data) {
+        self.contextInfo = data;
         /* set default page info */
-        var $defaultPage = self.$('[data-id="' + data.defaultPage + '"]');
-        if ($defaultPage.length > 0) {
-          $defaultPage.find('td.title').prepend('<span>*</span> ');
-          $defaultPage.addClass('default-page');
-        }
-        /* set breadcrumb title info */
-        var crumbs = data.breadcrumbs;
-        if (crumbs && crumbs.length) {
-          var $crumbs = self.$('.breadcrumbs a.crumb');
-          _.each(crumbs, function(crumb, idx) {
-            $crumbs.eq(idx).html(crumb.title);
-          });
-        }
+        self.setContextInfo();
       });
     },
     events: {
       'click .breadcrumbs a': 'breadcrumbClicked',
-      'change .select-all': 'selectAll'
+      'change .select-all': 'selectAll',
+      'change .breadcrumbs-container input[type="checkbox"]': 'selectFolder'
+    },
+    setContextInfo: function() {
+      var self = this;
+      var data = self.contextInfo;
+      var $defaultPage = self.$('[data-id="' + data.defaultPage + '"]');
+      if ($defaultPage.length > 0) {
+        $defaultPage.find('td.title').prepend('<span>*</span> ');
+        $defaultPage.addClass('default-page');
+      }
+      /* set breadcrumb title info */
+      var crumbs = data.breadcrumbs;
+      if (crumbs && crumbs.length) {
+        var $crumbs = self.$('.breadcrumbs a.crumb');
+        _.each(crumbs, function(crumb, idx) {
+          $crumbs.eq(idx).html(crumb.title);
+        });
+      }
+      if (data.object){
+        self.folderModel = new Result(data.object);
+        $('.context-buttons', self.$el).show();
+        if (self.selectedCollection.findWhere({UID: data.object.UID})){
+          $('input[type="checkbox"]', self.$breadcrumbs)[0].checked = true;
+        }
+        self.folderMenu = new ActionMenu({
+          app: self.app,
+          model: self.folderModel,
+          header: 'Actions on current folder',
+          canMove: false
+        });
+        $('.input-group-btn', self.$breadcrumbs).empty().append(self.folderMenu.render().el);
+      }else {
+        self.folderModel = null;
+      }
     },
     render: function() {
       var self = this;
       self.$el.html(self.template({
-        pathParts: self.app.queryHelper.getCurrentPath().split('/').slice(1),
+        pathParts: _.filter(
+          self.app.queryHelper.getCurrentPath().split('/').slice(1),
+          function(val) {
+            return val.length > 0;
+          }
+        ),
         status: self.app.status,
         statusType: self.app.statusType,
         activeColumns: self.app.activeColumns,
         availableColumns: self.app.availableColumns
       }));
+      self.$breadcrumbs = $('.breadcrumbs-container', self.$el);
 
       if (self.collection.length) {
         var container = self.$('tbody');
@@ -119,12 +151,24 @@ define([
       this.app.queryHelper.currentPath = path;
       this.collection.pager();
     },
+    selectFolder: function(e) {
+      var self = this;
+      if (self.folderModel){
+        if ($(e.target).is(':checked')) {
+          self.selectedCollection.add(self.folderModel);
+        } else {
+          this.selectedCollection.removeByUID(self.folderModel.attributes.UID);
+        }
+        self.setContextInfo();
+      }
+    },
     selectAll: function(e) {
       if ($(e.target).is(':checked')) {
         $('input[type="checkbox"]', this.$('tbody')).attr('checked', 'checked').change();
       } else {
         this.selectedCollection.remove(this.collection.models);
       }
+      this.setContextInfo();
     },
     toggleSelectAll: function(e) {
       var $el = $(e.target);
@@ -145,8 +189,10 @@ define([
         selector: 'tr',
         dragClass: 'structure-dragging',
         drop: function($el, delta) {
-          self.app.moveItem($el.attr('data-id'), delta, self.subsetIds);
-          self.storeOrder();
+          if(delta !== 0){
+            self.app.moveItem($el.attr('data-id'), delta, self.subsetIds);
+            self.storeOrder();
+          }
         }
       });
     },
diff --git a/js/patterns/structure/views/tablerow.js b/js/patterns/structure/views/tablerow.js
index 29ce67f..7c458fe 100644
--- a/js/patterns/structure/views/tablerow.js
+++ b/js/patterns/structure/views/tablerow.js
@@ -27,9 +27,9 @@ define([
   'jquery',
   'underscore',
   'backbone',
-  'text!js/patterns/structure/templates/tablerow.xml',
-  'bootstrap-dropdown'
-], function($, _, Backbone, TableRowTemplate) {
+  'js/patterns/structure/views/actionmenu',
+  'text!js/patterns/structure/templates/tablerow.xml'
+], function($, _, Backbone, ActionMenu, TableRowTemplate) {
   'use strict';
 
   var TableRowView = Backbone.View.extend({
@@ -38,15 +38,7 @@ define([
     template: _.template(TableRowTemplate),
     events: {
       'change input': 'itemSelected',
-      'click td.title a': 'itemClicked',
-      'click .cutItem a': 'cutClicked',
-      'click .copyItem a': 'copyClicked',
-      'click .pasteItem a': 'pasteClicked',
-      'click .move-top a': 'moveTopClicked',
-      'click .move-bottom a': 'moveBottomClicked',
-      'click .set-default-page a': 'setDefaultPageClicked',
-      'click .openItem a': 'openClicked',
-      'click .editItem a': 'editClicked'
+      'click td.title a': 'itemClicked'
     },
     initialize: function(options) {
       this.options = options;
@@ -64,9 +56,6 @@ define([
       data.attributes = self.model.attributes;
       data.activeColumns = self.app.activeColumns;
       data.availableColumns = self.app.availableColumns;
-      data.pasteAllowed = self.app.pasteAllowed;
-      data.canSetDefaultPage = self.app.setDefaultPageUrl;
-      data.inQueryMode = self.app.inQueryMode();
       self.$el.html(self.template(data));
       var attrs = self.model.attributes;
       self.$el.addClass('state-' + attrs['review_state']).addClass('type-' + attrs.Type); // jshint ignore:line
@@ -81,9 +70,12 @@ define([
 
       self.el.model = this.model;
 
-      self.$dropdown = self.$('.dropdown-toggle');
-      self.$dropdown.dropdown();
+      self.menu = new ActionMenu({
+        app: self.app,
+        model: self.model
+      });
 
+      $('.actionmenu-container', self.$el).append(self.menu.render().el);
       return this;
     },
     itemClicked: function(e) {
@@ -139,90 +131,6 @@ define([
 
       }
       this.app['last_selected'] = this.el; // jshint ignore:line
-    },
-    cutClicked: function(e) {
-      e.preventDefault();
-      this.cutCopyClicked('cut');
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    copyClicked: function(e) {
-      e.preventDefault();
-      this.cutCopyClicked('copy');
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    cutCopyClicked: function(operation) {
-      var self = this;
-      self.app.pasteOperation = operation;
-
-      self.app.pasteSelection = new Backbone.Collection();
-      self.app.pasteSelection.add(this.model);
-      self.app.setStatus(operation + ' 1 item');
-      self.app.pasteAllowed = true;
-      self.app.buttons.primary.get('paste').enable();
-    },
-    pasteClicked: function(e) {
-      e.preventDefault();
-      this.app.pasteEvent(this.app.buttons.primary.get('paste'), e, {
-        folder: this.model.attributes.path
-      });
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    moveTopClicked: function(e) {
-      e.preventDefault();
-      this.app.moveItem(this.model.attributes.id, 'top');
-    },
-    moveBottomClicked: function(e) {
-      e.preventDefault();
-      this.app.moveItem(this.model.attributes.id, 'bottom');
-    },
-    setDefaultPageClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      $.ajax({
-        url: self.app.getAjaxUrl(self.app.setDefaultPageUrl),
-        type: 'POST',
-        data: {
-          '_authenticator': $('[name="_authenticator"]').val(),
-          'id': this.$active.attr('data-id')
-        },
-        success: function(data) {
-          self.app.ajaxSuccessResponse.apply(self.app, [data]);
-        },
-        error: function(data) {
-          self.app.ajaxErrorResponse.apply(self.app, [data]);
-        }
-      });
-    },
-    getSelectedBaseUrl: function() {
-      var self = this;
-      return self.model.attributes.getURL;
-    },
-    getWindow: function() {
-      var win = window;
-      if (win.parent !== window) {
-        win = win.parent;
-      }
-      return win;
-    },
-    openUrl: function(url) {
-      var self = this;
-      var win = self.getWindow();
-      var keyEvent = this.app.keyEvent;
-      if (keyEvent && keyEvent.ctrlKey) {
-        win.open(url);
-      } else {
-        win.location = url;
-      }
-    },
-    openClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      self.openUrl(self.getSelectedBaseUrl() + '/view');
-    },
-    editClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      self.openUrl(self.getSelectedBaseUrl() + '/edit');
     }
   });
 
diff --git a/less/pattern.structure.less b/less/pattern.structure.less
index eb6e636..bd8d438 100644
--- a/less/pattern.structure.less
+++ b/less/pattern.structure.less
@@ -15,6 +15,16 @@
                 width: 15px;
             }
         }
+        .breadcrumbs-container{
+            .input-group{
+                .input-group-addon{
+                    padding: 2px 5px;
+                }
+
+                float: left;
+                padding-right: 5px;
+            }
+        }
     }
     .navbar {
         margin-bottom: 5px;
diff --git a/tests/fakeserver.js b/tests/fakeserver.js
index fdc305d..84b3354 100644
--- a/tests/fakeserver.js
+++ b/tests/fakeserver.js
@@ -533,6 +533,25 @@ define([
     });
   });
 
+  server.respondWith('GET', /context-info/, function(xhr, id) {
+    server.autoRespondAfter = 200;
+    var data = {
+      breadcrumbs: []
+    };
+    if (xhr.url.indexOf('http://') === -1){
+      _.each(xhr.url.split('/'), function(val) {
+        if (val !== '' && val !== 'context-info'){
+          val = val.charAt(0).toUpperCase() + val.slice(1);
+          data.breadcrumbs.push({
+            title: val
+          });
+        }
+      });
+      data.object = {UID: 'asdlfkjasdlfkjasdf', Title: 'News', path: '/news', Type: 'Folder'};
+    }
+    xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
+  });
+
   return server;
 
 });
diff --git a/tests/pattern-structure-test.js b/tests/pattern-structure-test.js
index dc3f7f5..3c26bf5 100644
--- a/tests/pattern-structure-test.js
+++ b/tests/pattern-structure-test.js
@@ -39,7 +39,7 @@ define([
                                  'tagsVocabularyUrl:/select2-test.json;' +
                                  'usersVocabularyUrl:/tests/json/users.json;' +
                                  'indexOptionsUrl:/tests/json/queryStringCriteria.json;' +
-                                 'contextInfoUrl:/contextInfo.json;' +
+                                 'contextInfoUrl:{path}/contextInfo;' +
                                  ' ">' +
         '</div>');
 
@@ -55,6 +55,18 @@ define([
           end = start + batch.size;
         }
         var items = [];
+        items.push({
+          UID: '123sdfasdfFolder',
+          getURL: 'http://localhost:8081/folder',
+          path: '/folder',
+          Type: 'Folder',
+          Description: 'folder',
+          Title: 'Folder',
+          'review_state': 'published',
+          'is_folderish': true,
+          Subject: [],
+          id: 'folder'
+        });
         for (var i = start; i < end; i = i + 1) {
           items.push({
             UID: '123sdfasdf' + i,
@@ -87,8 +99,8 @@ define([
           msg: 'pasted'
         }));
       });
-      this.server.respondWith('GET', '/contextInfo.json', function (xhr, id) {
-        xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({
+      this.server.respondWith('GET', /contextInfo/, function (xhr, id) {
+        var data = {
           addButtons: [{
             id: 'page',
             title: 'Page',
@@ -96,8 +108,23 @@ define([
           },{
             id: 'folder',
             title: 'Folder'
-          }]
-        }));
+          }],
+        };
+        if (xhr.url.indexOf('folder') !== -1){
+          data.object = {
+            UID: '123sdfasdfFolder',
+            getURL: 'http://localhost:8081/folder',
+            path: '/folder',
+            Type: 'Folder',
+            Description: 'folder',
+            Title: 'Folder',
+            'review_state': 'published',
+            'is_folderish': true,
+            Subject: [],
+            id: 'folder'
+          };
+        }
+        xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
       });
 
       this.clock = sinon.useFakeTimers();
@@ -160,10 +187,10 @@ define([
     it('per page', function() {
       registry.scan(this.$el);
       this.clock.tick(1000);
-      expect(this.$el.find('.itemRow').length).to.equal(15);
+      expect(this.$el.find('.itemRow').length).to.equal(16);
       this.$el.find('.serverhowmany30 a').trigger('click');
       this.clock.tick(1000);
-      expect(this.$el.find('.itemRow').length).to.equal(30);
+      expect(this.$el.find('.itemRow').length).to.equal(31);
     });
 
     it('test paging does not apply overflow hidden to parent', function() {
@@ -243,7 +270,7 @@ define([
       var $item = this.$el.find('table th .select-all');
       $item[0].checked = true;
       $item.trigger('change');
-      expect(this.$el.find('#selected').html()).to.contain('15');
+      expect(this.$el.find('#selected').html()).to.contain('16');
 
     });
 
@@ -254,11 +281,41 @@ define([
       var $item = this.$el.find('table th .select-all');
       $item[0].checked = true;
       $item.trigger('change');
-      expect(this.$el.find('#selected').html()).to.contain('15');
+      expect(this.$el.find('#selected').html()).to.contain('16');
       $item[0].checked = false;
       $item.trigger('change');
       expect(this.$el.find('#selected').html()).to.contain('0');
     });
 
+    it('test current folder buttons do not show on root', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      expect(this.$el.find('.context-buttons').length).to.equal(0);
+    });
+
+    it('test current folder buttons do show on subfolder', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      var $item = this.$el.find('.itemRow').eq(0);
+      $('.title a', $item).trigger('click');
+      this.clock.tick(1000);
+      expect(this.$el.find('.context-buttons').length).to.equal(1);
+    });
+
+    it('test select current folder', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      var $item = this.$el.find('.itemRow').eq(0);
+      $('.title a', $item).trigger('click');
+      this.clock.tick(1000);
+      var $checkbox = $('.breadcrumbs-container input[type="checkbox"]', this.$el);
+      $checkbox[0].checked = true;
+      $checkbox.trigger('change');
+      expect(this.$el.find('#selected').html()).to.contain('1');
+    });
+
   });
 });


Repository: mockup
Branch: refs/heads/master
Date: 2014-03-08T12:18:24Z
Author: Rok Garbas (garbas) <rok at garbas.si>
Commit: https://github.com/plone/mockup/commit/0d78aad7696285af3016bb853d053c2fa9baf0ea

Merge pull request #338 from plone/structure-context-improvements

provide folder context actions

Files changed:
A js/patterns/structure/templates/actionmenu.xml
A js/patterns/structure/views/actionmenu.js
M js/patterns/structure/pattern.js
M js/patterns/structure/templates/table.xml
M js/patterns/structure/templates/tablerow.xml
M js/patterns/structure/views/table.js
M js/patterns/structure/views/tablerow.js
M less/pattern.structure.less
M tests/fakeserver.js
M tests/pattern-structure-test.js

diff --git a/js/patterns/structure/pattern.js b/js/patterns/structure/pattern.js
index f09f758..a6cf4c8 100644
--- a/js/patterns/structure/pattern.js
+++ b/js/patterns/structure/pattern.js
@@ -22,7 +22,7 @@
  *                             tagsVocabularyUrl:/select2-test.json;
  *                             usersVocabularyUrl:/tests/json/users.json;
  *                             indexOptionsUrl:/tests/json/queryStringCriteria.json;
- *                             contextInfoUrl:/tests/json/contextInfo.json;"></div>
+ *                             contextInfoUrl:{path}/context-info;"></div>
  *
  * License:
  *    Copyright (C) 2010 Plone Foundation
diff --git a/js/patterns/structure/templates/actionmenu.xml b/js/patterns/structure/templates/actionmenu.xml
new file mode 100644
index 0000000..2db76a0
--- /dev/null
+++ b/js/patterns/structure/templates/actionmenu.xml
@@ -0,0 +1,25 @@
+<a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" href="#">
+  <span class="glyphicon glyphicon-cog"></i>
+  <span class="caret"></span>
+</a>
+<ul class="dropdown-menu">
+  <% if(header) { %>
+    <li class="dropdown-header"><%- header %></li>
+    <li class="divider"></li>
+  <% } %>
+  <li class="cutItem"><a href="#">Cut</a></li>
+  <li class="copyItem"><a href="#">Copy</a></li>
+  <% if(pasteAllowed && attributes.is_folderish){ %>
+    <li class="pasteItem"><a href="#">Paste</a></li>
+  <% } %>
+  <% if(!inQueryMode && canMove){ %>
+    <li class="move-top"><a href="#">Move to top of folder</a></li>
+    <li class="move-bottom"><a href="#">Move to bottom of folder</a></li>
+  <% } %>
+  <% if(!attributes.is_folderish && canSetDefaultPage){ %>
+    <li class="set-default-page"><a href="#">Set as default page</a></li>
+  <% } %>
+  <li class="openItem"><a href="#">Open</a></li>
+  <li class="editItem"><a href="#">Edit</a></li>
+</ul>
+
diff --git a/js/patterns/structure/templates/table.xml b/js/patterns/structure/templates/table.xml
index 64ca80a..429d67b 100644
--- a/js/patterns/structure/templates/table.xml
+++ b/js/patterns/structure/templates/table.xml
@@ -3,19 +3,30 @@
 </div>
 <table class="table table-striped table-bordered">
   <thead>
-    <tr class="breadcrumbs">
-        <td colspan="<%= activeColumns.length + 3 %>">
+    <tr class="breadcrumbs-container">
+      <td colspan="<%= activeColumns.length + 3 %>">
+        <% if(pathParts.length > 0) { %>
+          <div class="input-group context-buttons" style="display:none">
+            <span class="input-group-addon">
+              <input type="checkbox" />
+            </span>
+            <div class="input-group-btn">
+            </div>
+          </div>
+        <% } %>
+        <div class="breadcrumbs">
           <a href="#" data-path="/">
-              <span class="icon icon-home"></span> /
+            <span class="glyphicon glyphicon-home"></span> /
           </a>
-        <% _.each(pathParts, function(part, idx, list){
-          if(part){
-            if(idx > 0){ %>
-              /
-            <% } %>
-            <a href="#" class="crumb" data-path="<%- part %>"><%- part %></a>
-          <% }
-        }); %>
+          <% _.each(pathParts, function(part, idx, list){
+            if(part){
+              if(idx > 0){ %>
+                /
+              <% } %>
+              <a href="#" class="crumb" data-path="<%- part %>"><%- part %></a>
+            <% }
+          }); %>
+        </div>
       </td>
     </tr>
     <tr>
diff --git a/js/patterns/structure/templates/tablerow.xml b/js/patterns/structure/templates/tablerow.xml
index 9cd8bab..27406d7 100644
--- a/js/patterns/structure/templates/tablerow.xml
+++ b/js/patterns/structure/templates/tablerow.xml
@@ -18,27 +18,5 @@
     <td class="<%- column %>"><%- attributes[column] %></td>
   <% } %>
 <% }); %>
-<td>
-  <div class="btn-group">
-    <a class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" href="#">
-      <span class="glyphicon glyphicon-cog"></i>
-      <span class="caret"></span>
-    </a>
-    <ul class="dropdown-menu">
-      <li class="cutItem"><a href="#">Cut</a></li>
-      <li class="copyItem"><a href="#">Copy</a></li>
-      <% if(pasteAllowed && attributes.is_folderish){ %>
-        <li class="pasteItem"><a href="#">Paste</a></li>
-      <% } %>
-      <% if(!inQueryMode){ %>
-        <li class="move-top"><a href="#">Move to top of folder</a></li>
-        <li class="move-bottom"><a href="#">Move to bottom of folder</a></li>
-      <% } %>
-      <% if(!attributes.is_folderish && canSetDefaultPage){ %>
-        <li class="set-default-page"><a href="#">Set as default page</a></li>
-      <% } %>
-      <li class="openItem"><a href="#">Open</a></li>
-      <li class="editItem"><a href="#">Edit</a></li>
-    </ul>
-  </div>
+<td class="actionmenu-container">
 </td>
diff --git a/js/patterns/structure/views/actionmenu.js b/js/patterns/structure/views/actionmenu.js
new file mode 100644
index 0000000..3965ab0
--- /dev/null
+++ b/js/patterns/structure/views/actionmenu.js
@@ -0,0 +1,171 @@
+// Author: Nathan Van Gheem
+// Contact: nathan at vangheem.us
+// Version: 1.0
+//
+// Description:
+//
+// License:
+//
+// Copyright (C) 2010 Plone Foundation
+//
+// This program is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License as published by the Free
+// Software Foundation; either version 2 of the License.
+//
+// This program is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+// more details.
+//
+// You should have received a copy of the GNU General Public License along with
+// this program; if not, write to the Free Software Foundation, Inc., 51
+// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+
+/* global alert:true */
+
+define([
+  'jquery',
+  'underscore',
+  'backbone',
+  'js/ui/views/base',
+  'mockup-utils',
+  'text!js/patterns/structure/templates/actionmenu.xml',
+  'bootstrap-dropdown'
+], function($, _, Backbone, BaseView, utils, ActionMenuTemplate) {
+  'use strict';
+
+  var ActionMenu = BaseView.extend({
+    className: 'btn-group actionmenu',
+    template: _.template(ActionMenuTemplate),
+    events: {
+      'click .cutItem a': 'cutClicked',
+      'click .copyItem a': 'copyClicked',
+      'click .pasteItem a': 'pasteClicked',
+      'click .move-top a': 'moveTopClicked',
+      'click .move-bottom a': 'moveBottomClicked',
+      'click .set-default-page a': 'setDefaultPageClicked',
+      'click .openItem a': 'openClicked',
+      'click .editItem a': 'editClicked'
+    },
+    initialize: function(options) {
+      this.options = options;
+      this.app = options.app;
+      this.model = options.model;
+      this.selectedCollection = this.app.selectedCollection;
+      if (options.canMove === false){
+        this.canMove = false;
+      }else {
+        this.canMove = true;
+      }
+    },
+    cutClicked: function(e) {
+      e.preventDefault();
+      this.cutCopyClicked('cut');
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    copyClicked: function(e) {
+      e.preventDefault();
+      this.cutCopyClicked('copy');
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    cutCopyClicked: function(operation) {
+      var self = this;
+      self.app.pasteOperation = operation;
+
+      self.app.pasteSelection = new Backbone.Collection();
+      self.app.pasteSelection.add(this.model);
+      self.app.setStatus(operation + ' 1 item');
+      self.app.pasteAllowed = true;
+      self.app.buttons.primary.get('paste').enable();
+    },
+    pasteClicked: function(e) {
+      e.preventDefault();
+      this.app.pasteEvent(this.app.buttons.primary.get('paste'), e, {
+        folder: this.model.attributes.path
+      });
+      this.app.collection.pager(); // reload to be able to now show paste button
+    },
+    moveTopClicked: function(e) {
+      e.preventDefault();
+      this.app.moveItem(this.model.attributes.id, 'top');
+    },
+    moveBottomClicked: function(e) {
+      e.preventDefault();
+      this.app.moveItem(this.model.attributes.id, 'bottom');
+    },
+    setDefaultPageClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      $.ajax({
+        url: self.app.getAjaxUrl(self.app.setDefaultPageUrl),
+        type: 'POST',
+        data: {
+          '_authenticator': $('[name="_authenticator"]').val(),
+          'id': this.$active.attr('data-id')
+        },
+        success: function(data) {
+          self.app.ajaxSuccessResponse.apply(self.app, [data]);
+        },
+        error: function(data) {
+          self.app.ajaxErrorResponse.apply(self.app, [data]);
+        }
+      });
+    },
+    getSelectedBaseUrl: function() {
+      var self = this;
+      return self.model.attributes.getURL;
+    },
+    getWindow: function() {
+      var win = window;
+      if (win.parent !== window) {
+        win = win.parent;
+      }
+      return win;
+    },
+    openUrl: function(url) {
+      var self = this;
+      var win = self.getWindow();
+      var keyEvent = this.app.keyEvent;
+      if (keyEvent && keyEvent.ctrlKey) {
+        win.open(url);
+      } else {
+        win.location = url;
+      }
+    },
+    openClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      self.openUrl(self.getSelectedBaseUrl() + '/view');
+    },
+    editClicked: function(e) {
+      e.preventDefault();
+      var self = this;
+      self.openUrl(self.getSelectedBaseUrl() + '/edit');
+    },
+    render: function() {
+      var self = this;
+      self.$el.empty();
+
+      var data = this.model.toJSON();
+      data.attributes = self.model.attributes;
+      data.pasteAllowed = self.app.pasteAllowed;
+      data.canSetDefaultPage = self.app.setDefaultPageUrl;
+      data.inQueryMode = self.app.inQueryMode();
+      data.header = self.options.header;
+      data.canMove = self.canMove;
+
+      self.$el.html(self.template(data));
+
+      self.$dropdown = self.$('.dropdown-toggle');
+      self.$dropdown.dropdown();
+
+      if (self.options.className){
+        self.$el.addClass(self.options.className);
+      }
+      return this;
+    }
+  });
+
+  return ActionMenu;
+});
diff --git a/js/patterns/structure/views/table.js b/js/patterns/structure/views/table.js
index 40c45f6..99bf7ff 100644
--- a/js/patterns/structure/views/table.js
+++ b/js/patterns/structure/views/table.js
@@ -31,9 +31,11 @@ define([
   'text!js/patterns/structure/templates/table.xml',
   'js/ui/views/base',
   'mockup-patterns-sortable',
-  'mockup-patterns-moment'
+  'mockup-patterns-moment',
+  'js/patterns/structure/models/result',
+  'js/patterns/structure/views/actionmenu'
 ], function($, _, Backbone, TableRowView, TableTemplate, BaseView, Sortable,
-            Moment) {
+            Moment, Result, ActionMenu) {
   'use strict';
 
   var TableView = BaseView.extend({
@@ -49,37 +51,67 @@ define([
       self.listenTo(self.selectedCollection, 'reset', self.render);
       self.collection.pager();
       self.subsetIds = [];
+      self.contextInfo = self.folderModel = self.folderMenu = null;
 
       self.app.on('context-info-loaded', function(data) {
+        self.contextInfo = data;
         /* set default page info */
-        var $defaultPage = self.$('[data-id="' + data.defaultPage + '"]');
-        if ($defaultPage.length > 0) {
-          $defaultPage.find('td.title').prepend('<span>*</span> ');
-          $defaultPage.addClass('default-page');
-        }
-        /* set breadcrumb title info */
-        var crumbs = data.breadcrumbs;
-        if (crumbs && crumbs.length) {
-          var $crumbs = self.$('.breadcrumbs a.crumb');
-          _.each(crumbs, function(crumb, idx) {
-            $crumbs.eq(idx).html(crumb.title);
-          });
-        }
+        self.setContextInfo();
       });
     },
     events: {
       'click .breadcrumbs a': 'breadcrumbClicked',
-      'change .select-all': 'selectAll'
+      'change .select-all': 'selectAll',
+      'change .breadcrumbs-container input[type="checkbox"]': 'selectFolder'
+    },
+    setContextInfo: function() {
+      var self = this;
+      var data = self.contextInfo;
+      var $defaultPage = self.$('[data-id="' + data.defaultPage + '"]');
+      if ($defaultPage.length > 0) {
+        $defaultPage.find('td.title').prepend('<span>*</span> ');
+        $defaultPage.addClass('default-page');
+      }
+      /* set breadcrumb title info */
+      var crumbs = data.breadcrumbs;
+      if (crumbs && crumbs.length) {
+        var $crumbs = self.$('.breadcrumbs a.crumb');
+        _.each(crumbs, function(crumb, idx) {
+          $crumbs.eq(idx).html(crumb.title);
+        });
+      }
+      if (data.object){
+        self.folderModel = new Result(data.object);
+        $('.context-buttons', self.$el).show();
+        if (self.selectedCollection.findWhere({UID: data.object.UID})){
+          $('input[type="checkbox"]', self.$breadcrumbs)[0].checked = true;
+        }
+        self.folderMenu = new ActionMenu({
+          app: self.app,
+          model: self.folderModel,
+          header: 'Actions on current folder',
+          canMove: false
+        });
+        $('.input-group-btn', self.$breadcrumbs).empty().append(self.folderMenu.render().el);
+      }else {
+        self.folderModel = null;
+      }
     },
     render: function() {
       var self = this;
       self.$el.html(self.template({
-        pathParts: self.app.queryHelper.getCurrentPath().split('/').slice(1),
+        pathParts: _.filter(
+          self.app.queryHelper.getCurrentPath().split('/').slice(1),
+          function(val) {
+            return val.length > 0;
+          }
+        ),
         status: self.app.status,
         statusType: self.app.statusType,
         activeColumns: self.app.activeColumns,
         availableColumns: self.app.availableColumns
       }));
+      self.$breadcrumbs = $('.breadcrumbs-container', self.$el);
 
       if (self.collection.length) {
         var container = self.$('tbody');
@@ -119,12 +151,24 @@ define([
       this.app.queryHelper.currentPath = path;
       this.collection.pager();
     },
+    selectFolder: function(e) {
+      var self = this;
+      if (self.folderModel){
+        if ($(e.target).is(':checked')) {
+          self.selectedCollection.add(self.folderModel);
+        } else {
+          this.selectedCollection.removeByUID(self.folderModel.attributes.UID);
+        }
+        self.setContextInfo();
+      }
+    },
     selectAll: function(e) {
       if ($(e.target).is(':checked')) {
         $('input[type="checkbox"]', this.$('tbody')).attr('checked', 'checked').change();
       } else {
         this.selectedCollection.remove(this.collection.models);
       }
+      this.setContextInfo();
     },
     toggleSelectAll: function(e) {
       var $el = $(e.target);
@@ -145,8 +189,10 @@ define([
         selector: 'tr',
         dragClass: 'structure-dragging',
         drop: function($el, delta) {
-          self.app.moveItem($el.attr('data-id'), delta, self.subsetIds);
-          self.storeOrder();
+          if(delta !== 0){
+            self.app.moveItem($el.attr('data-id'), delta, self.subsetIds);
+            self.storeOrder();
+          }
         }
       });
     },
diff --git a/js/patterns/structure/views/tablerow.js b/js/patterns/structure/views/tablerow.js
index 29ce67f..7c458fe 100644
--- a/js/patterns/structure/views/tablerow.js
+++ b/js/patterns/structure/views/tablerow.js
@@ -27,9 +27,9 @@ define([
   'jquery',
   'underscore',
   'backbone',
-  'text!js/patterns/structure/templates/tablerow.xml',
-  'bootstrap-dropdown'
-], function($, _, Backbone, TableRowTemplate) {
+  'js/patterns/structure/views/actionmenu',
+  'text!js/patterns/structure/templates/tablerow.xml'
+], function($, _, Backbone, ActionMenu, TableRowTemplate) {
   'use strict';
 
   var TableRowView = Backbone.View.extend({
@@ -38,15 +38,7 @@ define([
     template: _.template(TableRowTemplate),
     events: {
       'change input': 'itemSelected',
-      'click td.title a': 'itemClicked',
-      'click .cutItem a': 'cutClicked',
-      'click .copyItem a': 'copyClicked',
-      'click .pasteItem a': 'pasteClicked',
-      'click .move-top a': 'moveTopClicked',
-      'click .move-bottom a': 'moveBottomClicked',
-      'click .set-default-page a': 'setDefaultPageClicked',
-      'click .openItem a': 'openClicked',
-      'click .editItem a': 'editClicked'
+      'click td.title a': 'itemClicked'
     },
     initialize: function(options) {
       this.options = options;
@@ -64,9 +56,6 @@ define([
       data.attributes = self.model.attributes;
       data.activeColumns = self.app.activeColumns;
       data.availableColumns = self.app.availableColumns;
-      data.pasteAllowed = self.app.pasteAllowed;
-      data.canSetDefaultPage = self.app.setDefaultPageUrl;
-      data.inQueryMode = self.app.inQueryMode();
       self.$el.html(self.template(data));
       var attrs = self.model.attributes;
       self.$el.addClass('state-' + attrs['review_state']).addClass('type-' + attrs.Type); // jshint ignore:line
@@ -81,9 +70,12 @@ define([
 
       self.el.model = this.model;
 
-      self.$dropdown = self.$('.dropdown-toggle');
-      self.$dropdown.dropdown();
+      self.menu = new ActionMenu({
+        app: self.app,
+        model: self.model
+      });
 
+      $('.actionmenu-container', self.$el).append(self.menu.render().el);
       return this;
     },
     itemClicked: function(e) {
@@ -139,90 +131,6 @@ define([
 
       }
       this.app['last_selected'] = this.el; // jshint ignore:line
-    },
-    cutClicked: function(e) {
-      e.preventDefault();
-      this.cutCopyClicked('cut');
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    copyClicked: function(e) {
-      e.preventDefault();
-      this.cutCopyClicked('copy');
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    cutCopyClicked: function(operation) {
-      var self = this;
-      self.app.pasteOperation = operation;
-
-      self.app.pasteSelection = new Backbone.Collection();
-      self.app.pasteSelection.add(this.model);
-      self.app.setStatus(operation + ' 1 item');
-      self.app.pasteAllowed = true;
-      self.app.buttons.primary.get('paste').enable();
-    },
-    pasteClicked: function(e) {
-      e.preventDefault();
-      this.app.pasteEvent(this.app.buttons.primary.get('paste'), e, {
-        folder: this.model.attributes.path
-      });
-      this.app.collection.pager(); // reload to be able to now show paste button
-    },
-    moveTopClicked: function(e) {
-      e.preventDefault();
-      this.app.moveItem(this.model.attributes.id, 'top');
-    },
-    moveBottomClicked: function(e) {
-      e.preventDefault();
-      this.app.moveItem(this.model.attributes.id, 'bottom');
-    },
-    setDefaultPageClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      $.ajax({
-        url: self.app.getAjaxUrl(self.app.setDefaultPageUrl),
-        type: 'POST',
-        data: {
-          '_authenticator': $('[name="_authenticator"]').val(),
-          'id': this.$active.attr('data-id')
-        },
-        success: function(data) {
-          self.app.ajaxSuccessResponse.apply(self.app, [data]);
-        },
-        error: function(data) {
-          self.app.ajaxErrorResponse.apply(self.app, [data]);
-        }
-      });
-    },
-    getSelectedBaseUrl: function() {
-      var self = this;
-      return self.model.attributes.getURL;
-    },
-    getWindow: function() {
-      var win = window;
-      if (win.parent !== window) {
-        win = win.parent;
-      }
-      return win;
-    },
-    openUrl: function(url) {
-      var self = this;
-      var win = self.getWindow();
-      var keyEvent = this.app.keyEvent;
-      if (keyEvent && keyEvent.ctrlKey) {
-        win.open(url);
-      } else {
-        win.location = url;
-      }
-    },
-    openClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      self.openUrl(self.getSelectedBaseUrl() + '/view');
-    },
-    editClicked: function(e) {
-      e.preventDefault();
-      var self = this;
-      self.openUrl(self.getSelectedBaseUrl() + '/edit');
     }
   });
 
diff --git a/less/pattern.structure.less b/less/pattern.structure.less
index eb6e636..bd8d438 100644
--- a/less/pattern.structure.less
+++ b/less/pattern.structure.less
@@ -15,6 +15,16 @@
                 width: 15px;
             }
         }
+        .breadcrumbs-container{
+            .input-group{
+                .input-group-addon{
+                    padding: 2px 5px;
+                }
+
+                float: left;
+                padding-right: 5px;
+            }
+        }
     }
     .navbar {
         margin-bottom: 5px;
diff --git a/tests/fakeserver.js b/tests/fakeserver.js
index fdc305d..84b3354 100644
--- a/tests/fakeserver.js
+++ b/tests/fakeserver.js
@@ -533,6 +533,25 @@ define([
     });
   });
 
+  server.respondWith('GET', /context-info/, function(xhr, id) {
+    server.autoRespondAfter = 200;
+    var data = {
+      breadcrumbs: []
+    };
+    if (xhr.url.indexOf('http://') === -1){
+      _.each(xhr.url.split('/'), function(val) {
+        if (val !== '' && val !== 'context-info'){
+          val = val.charAt(0).toUpperCase() + val.slice(1);
+          data.breadcrumbs.push({
+            title: val
+          });
+        }
+      });
+      data.object = {UID: 'asdlfkjasdlfkjasdf', Title: 'News', path: '/news', Type: 'Folder'};
+    }
+    xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
+  });
+
   return server;
 
 });
diff --git a/tests/pattern-structure-test.js b/tests/pattern-structure-test.js
index dc3f7f5..3c26bf5 100644
--- a/tests/pattern-structure-test.js
+++ b/tests/pattern-structure-test.js
@@ -39,7 +39,7 @@ define([
                                  'tagsVocabularyUrl:/select2-test.json;' +
                                  'usersVocabularyUrl:/tests/json/users.json;' +
                                  'indexOptionsUrl:/tests/json/queryStringCriteria.json;' +
-                                 'contextInfoUrl:/contextInfo.json;' +
+                                 'contextInfoUrl:{path}/contextInfo;' +
                                  ' ">' +
         '</div>');
 
@@ -55,6 +55,18 @@ define([
           end = start + batch.size;
         }
         var items = [];
+        items.push({
+          UID: '123sdfasdfFolder',
+          getURL: 'http://localhost:8081/folder',
+          path: '/folder',
+          Type: 'Folder',
+          Description: 'folder',
+          Title: 'Folder',
+          'review_state': 'published',
+          'is_folderish': true,
+          Subject: [],
+          id: 'folder'
+        });
         for (var i = start; i < end; i = i + 1) {
           items.push({
             UID: '123sdfasdf' + i,
@@ -87,8 +99,8 @@ define([
           msg: 'pasted'
         }));
       });
-      this.server.respondWith('GET', '/contextInfo.json', function (xhr, id) {
-        xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify({
+      this.server.respondWith('GET', /contextInfo/, function (xhr, id) {
+        var data = {
           addButtons: [{
             id: 'page',
             title: 'Page',
@@ -96,8 +108,23 @@ define([
           },{
             id: 'folder',
             title: 'Folder'
-          }]
-        }));
+          }],
+        };
+        if (xhr.url.indexOf('folder') !== -1){
+          data.object = {
+            UID: '123sdfasdfFolder',
+            getURL: 'http://localhost:8081/folder',
+            path: '/folder',
+            Type: 'Folder',
+            Description: 'folder',
+            Title: 'Folder',
+            'review_state': 'published',
+            'is_folderish': true,
+            Subject: [],
+            id: 'folder'
+          };
+        }
+        xhr.respond(200, { 'Content-Type': 'application/json' }, JSON.stringify(data));
       });
 
       this.clock = sinon.useFakeTimers();
@@ -160,10 +187,10 @@ define([
     it('per page', function() {
       registry.scan(this.$el);
       this.clock.tick(1000);
-      expect(this.$el.find('.itemRow').length).to.equal(15);
+      expect(this.$el.find('.itemRow').length).to.equal(16);
       this.$el.find('.serverhowmany30 a').trigger('click');
       this.clock.tick(1000);
-      expect(this.$el.find('.itemRow').length).to.equal(30);
+      expect(this.$el.find('.itemRow').length).to.equal(31);
     });
 
     it('test paging does not apply overflow hidden to parent', function() {
@@ -243,7 +270,7 @@ define([
       var $item = this.$el.find('table th .select-all');
       $item[0].checked = true;
       $item.trigger('change');
-      expect(this.$el.find('#selected').html()).to.contain('15');
+      expect(this.$el.find('#selected').html()).to.contain('16');
 
     });
 
@@ -254,11 +281,41 @@ define([
       var $item = this.$el.find('table th .select-all');
       $item[0].checked = true;
       $item.trigger('change');
-      expect(this.$el.find('#selected').html()).to.contain('15');
+      expect(this.$el.find('#selected').html()).to.contain('16');
       $item[0].checked = false;
       $item.trigger('change');
       expect(this.$el.find('#selected').html()).to.contain('0');
     });
 
+    it('test current folder buttons do not show on root', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      expect(this.$el.find('.context-buttons').length).to.equal(0);
+    });
+
+    it('test current folder buttons do show on subfolder', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      var $item = this.$el.find('.itemRow').eq(0);
+      $('.title a', $item).trigger('click');
+      this.clock.tick(1000);
+      expect(this.$el.find('.context-buttons').length).to.equal(1);
+    });
+
+    it('test select current folder', function() {
+      registry.scan(this.$el);
+      var pattern = this.$el.data('patternStructure');
+      this.clock.tick(1000);
+      var $item = this.$el.find('.itemRow').eq(0);
+      $('.title a', $item).trigger('click');
+      this.clock.tick(1000);
+      var $checkbox = $('.breadcrumbs-container input[type="checkbox"]', this.$el);
+      $checkbox[0].checked = true;
+      $checkbox.trigger('change');
+      expect(this.$el.find('#selected').html()).to.contain('1');
+    });
+
   });
 });




-------------------------------------------------------------------------------


More information about the Testbot mailing list