diff --git a/bower.json b/bower.json
index 8c3f434..ee11c2e 100644
--- a/bower.json
+++ b/bower.json
@@ -23,6 +23,7 @@
"angular-animate": "1.2.14",
"angular-loading-bar": "0.4.2",
"angular-sanitize": "1.2.14",
- "angular-bootstrap": "0.10.0"
+ "angular-bootstrap": "0.10.0",
+ "angular-bootstrap-nav-tree": "*"
}
}
diff --git a/src/plone/app/angularjs/api/api.py b/src/plone/app/angularjs/api/api.py
index 622eff4..edb9896 100644
--- a/src/plone/app/angularjs/api/api.py
+++ b/src/plone/app/angularjs/api/api.py
@@ -1,4 +1,7 @@
# -*- coding: utf-8 -*-
+from Acquisition import aq_chain
+from Products.CMFCore.interfaces import IContentish
+from Products.CMFCore.interfaces import IFolderish
from Products.Five.browser.pagetemplatefile import ViewPageTemplateFile
from Products.Five.browser import BrowserView
from zope.component.hooks import getSite
@@ -118,3 +121,36 @@ def _get_children(context):
) if brain.exclude_from_nav is not True
]
)
+
+ def folder_children(self, request):
+ portal = getSite()
+ portal_path = '/'.join(portal.getPhysicalPath())
+ path = request.get('path')
+ if not path:
+ path = portal_path
+ else:
+ path = portal_path + path
+ try:
+ folder = portal.restrictedTraverse(path)
+ except KeyError:
+ return json.dumps([])
+ if not IFolderish.providedBy(folder):
+ for item in aq_chain(folder):
+ if IFolderish.providedBy(item):
+ folder = item
+ break
+ return json.dumps(
+ [
+ {
+ 'id': obj[1].id,
+ 'title': obj[1].title,
+ 'label': obj[1].title,
+ 'description': obj[1].description,
+ 'url': '/'.join(obj[1].getPhysicalPath()),
+ 'children': []
+ }
+ for obj in folder.objectItems()
+ if IContentish.providedBy(obj[1])
+ and obj[1].exclude_from_nav is not True
+ ]
+ )
diff --git a/src/plone/app/angularjs/app/index.html b/src/plone/app/angularjs/app/index.html
index 07020c8..37d63f1 100644
--- a/src/plone/app/angularjs/app/index.html
+++ b/src/plone/app/angularjs/app/index.html
@@ -6,7 +6,9 @@
+
+
@@ -16,9 +18,11 @@
+
+
diff --git a/src/plone/app/angularjs/app/navigation-portlet.tpl.html b/src/plone/app/angularjs/app/navigation-portlet.tpl.html
index 2c78c06..b52197a 100644
--- a/src/plone/app/angularjs/app/navigation-portlet.tpl.html
+++ b/src/plone/app/angularjs/app/navigation-portlet.tpl.html
@@ -1,4 +1,4 @@
-
+
+
diff --git a/src/plone/app/angularjs/app/scripts/app.js b/src/plone/app/angularjs/app/scripts/app.js
index a13e0f2..3a48089 100644
--- a/src/plone/app/angularjs/app/scripts/app.js
+++ b/src/plone/app/angularjs/app/scripts/app.js
@@ -5,6 +5,7 @@ var ploneModule = angular.module(
'ngRoute',
'ngSanitize',
'ui.bootstrap',
+ 'angularBootstrapNavTree'
]
);
diff --git a/src/plone/app/angularjs/app/scripts/directives.js b/src/plone/app/angularjs/app/scripts/directives.js
index 190dee3..b714648 100644
--- a/src/plone/app/angularjs/app/scripts/directives.js
+++ b/src/plone/app/angularjs/app/scripts/directives.js
@@ -28,23 +28,3 @@ ploneModule.directive('navigationDirective',
};
}
);
-
-ploneModule.controller('NavigationPortletController',
- function($scope, $http) {
- 'use strict';
- var url = '++api++v1/navigation_tree';
- $http.get(url).success(function(data) {
- $scope.items = data;
- });
- }
-);
-
-ploneModule.directive('navigationPortletDirective',
- function() {
- 'use strict';
- return {
- templateUrl: 'navigation-portlet.tpl.html',
- controller: 'NavigationPortletController'
- };
- }
-);
diff --git a/src/plone/app/angularjs/app/scripts/navigation-portlet.js b/src/plone/app/angularjs/app/scripts/navigation-portlet.js
new file mode 100644
index 0000000..1d0bbee
--- /dev/null
+++ b/src/plone/app/angularjs/app/scripts/navigation-portlet.js
@@ -0,0 +1,65 @@
+var ploneModule;
+
+ploneModule.factory('reportTreeService', function($q, $http) {
+
+ var getTreeData = function(path) {
+ console.log('getTreeData(' + path + ')');
+ var deferred = $q.defer();
+ $http({
+ method: 'GET',
+ url: '++api++v1/folder_children',
+ params: {
+ path: path
+ }
+ }).then(function (response) {
+ deferred.resolve(response.data);
+ });
+ return deferred.promise;
+ };
+
+ return {
+ getTreeData: getTreeData
+ };
+
+});
+
+
+ploneModule.controller('NavigationPortletController',
+ function($scope, $location, reportTreeService) {
+ 'use strict';
+ $scope.location = $location;
+ $scope.folders = [];
+ var path = $scope.location.path();
+ console.log("PATH: " + path);
+ reportTreeService.getTreeData(path).then(function(data) {
+ $scope.folders = data;
+
+ $scope.my_tree_handler = function(branch) {
+ console.log('my_tree_handler(' + branch + ')');
+ $scope.output = "You selected: " + branch.label;
+ if (branch.label == 'Nachrichten') {
+ reportTreeService.getTreeData('/news').then(function(data) {
+ branch.children = data;
+ });
+ }
+ if (branch.label == 'Termine') {
+ reportTreeService.getTreeData('/events').then(function(data) {
+ branch.children = data;
+ });
+ }
+ };
+ });
+
+ }
+);
+
+
+ploneModule.directive('navigationPortletDirective',
+ function() {
+ 'use strict';
+ return {
+ templateUrl: 'navigation-portlet.tpl.html',
+ controller: 'NavigationPortletController'
+ };
+ }
+);
diff --git a/src/plone/app/angularjs/tests/test_api_folder_children.py b/src/plone/app/angularjs/tests/test_api_folder_children.py
new file mode 100644
index 0000000..921fa73
--- /dev/null
+++ b/src/plone/app/angularjs/tests/test_api_folder_children.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+from plone.app.angularjs.interfaces import IRestApi
+from plone.app.testing import setRoles
+from plone.app.testing import TEST_USER_ID
+from plone.app.angularjs.testing import\
+ PLONE_APP_ANGULARJS_INTEGRATION_TESTING
+from zope.component import getUtility
+
+import json
+import unittest2 as unittest
+
+
+class TestAngularJsFolderChildren(unittest.TestCase):
+
+ layer = PLONE_APP_ANGULARJS_INTEGRATION_TESTING
+
+ def setUp(self):
+ self.app = self.layer['app']
+ self.portal = self.layer['portal']
+ self.request = self.layer['request']
+ setRoles(self.portal, TEST_USER_ID, ['Manager'])
+ self.api = getUtility(IRestApi)
+
+ def test_empty_navigation(self):
+ self.assertEqual(
+ json.loads(self.api.folder_children(self.request)),
+ []
+ )
+
+ def test_folder_in_navigation(self):
+ self.portal.invokeFactory('Folder', 'folder1', title='Folder 1')
+
+ self.assertTrue(self.api.folder_children(self.request))
+ self.assertEqual(
+ json.loads(self.api.folder_children(self.request)),
+ [{
+ u'id': u'folder1',
+ u'title': u'Folder 1',
+ u'label': u'Folder 1',
+ u'description': u'',
+ u'url': '/plone/folder1',
+ u'children': []
+ }]
+ )
+
+ def test_do_not_show_excluded_from_nav_documents(self):
+ self.portal.invokeFactory('Folder', 'folder1', title='Folder 1')
+ self.portal.folder1.exclude_from_nav = True
+ self.portal.folder1.reindexObject(idxs=['exclude_from_nav'])
+
+ self.assertEqual(
+ len(json.loads(self.api.folder_children(self.request))),
+ 0
+ )
+
+ def test_folder_in_navigation_with_path(self):
+ self.portal.invokeFactory('Folder', 'folder1', title='Folder 1')
+ self.portal.folder1.invokeFactory(
+ 'Folder', 'folder2', title='Folder 2')
+ self.request.set('path', '/folder1')
+ self.assertTrue(
+ self.api.folder_children(self.request))
+ self.assertEqual(
+ json.loads(
+ self.api.folder_children(self.request)
+ ),
+ [{
+ u'id': u'folder2',
+ u'title': u'Folder 2',
+ u'label': u'Folder 2',
+ u'description': u'',
+ u'url': '/plone/folder1/folder2',
+ u'children': []
+ }]
+ )
+
+ def test_document_returns_parent_folder(self):
+ self.portal.invokeFactory('Folder', 'folder1', title='Folder 1')
+ self.portal.folder1.invokeFactory(
+ 'Document', 'doc1', title='Document 1')
+ self.request.set('path', '/folder1/doc1')
+ self.assertTrue(
+ self.api.folder_children(self.request))
+ self.assertEqual(
+ json.loads(
+ self.api.folder_children(self.request)
+ )[0]['id'],
+ u'doc1'
+ )