Skip to content
This repository was archived by the owner on Sep 16, 2021. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
language: php

php:
- 5.5
- 5.6
- 7.0
- hhvm
- 7.1

sudo: false

Expand Down
132 changes: 80 additions & 52 deletions Resources/assets/js/adapter/fancytree.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,19 @@ import '../../css/fontawesome-style.css'

var cache = new Map();

function getPropertyFromString(propertyPath, list) {
var isOptional = propertyPath.substr(0, 1) === '?';
var props = propertyPath.substr(1).split('.');
var currentNode = list;
for (let prop in props) {
currentNode = currentNode[props[prop]];

if (undefined === currentNode) {
if (isOptional) {
break;
}
function getPropertyFromString(name, list) {
var isOptional = name.substr(0, 1) === '?';
var nameWithoutPrefix = (isOptional ? name.substr(1) : name);

throw 'Attribute "' + props[prop] + '" does not exists';
if (undefined === list[nameWithoutPrefix]) {
if (isOptional) {
return undefined;
}

throw 'Attribute "' + props[prop] + '" does not exists';
}

return currentNode;
return list[nameWithoutPrefix];
}

/**
Expand Down Expand Up @@ -60,6 +56,8 @@ export class FancytreeAdapter {
this.tree = null;
// the tree element (jQuery)
this.$tree = null;
// a map of path and related keys
this.pathKeyMap = {};
}

bindToElement($elem) {
Expand All @@ -74,23 +72,31 @@ export class FancytreeAdapter {
this.$tree = $elem;
var actions = this.actions;
var requestNode = this.requestNode;
var requestNodeToFancytreeNode = function (requestNode) {
var requestNodeToFancytreeNode = (requestNode) => {
if (requestNode.length === 0) {
return;
}

if ('//' == requestNode.path || '/' == requestNode.path) {
return requestNodeToFancytreeNode(requestNode.children[Object.keys(requestNode.children)[0]]);
}

var key = "" + jQuery.ui.fancytree._nextNodeKey++;
var fancytreeNode = {
title: requestNode.label,
key: requestNode.node_name,
key: key,
children: [],
actions: {}
actions: {},
refPath: requestNode.path.replace('\/', '/').replace('//', '/')
};

this.pathKeyMap[fancytreeNode.refPath] = key;

for (let actionName in actions) {
var action = actions[actionName];
var url = action.url;
if (typeof action.url == 'object' && action.url.hasOwnProperty('data')) {
url = getPropertyFromString(action.url.data, requestNode);
url = getPropertyFromString(action.url.data, requestNode.descriptors);
}

if (url === undefined) {
Expand All @@ -112,9 +118,13 @@ export class FancytreeAdapter {
childrenCount++;
}

if (childrenCount) {
if (0 != childrenCount) {
fancytreeNode.folder = true;
fancytreeNode.lazy = true;

if (0 === fancytreeNode.children.length) {
fancytreeNode.children = null;
}
}

return fancytreeNode;
Expand All @@ -128,7 +138,7 @@ export class FancytreeAdapter {

// lazy load the children when a node is collapsed
lazyLoad: function (event, data) {
var path = data.node.getKeyPath();
var path = data.node.data.refPath;
if (useCache && cache.has(path)) {
data.result = cache.get(path);
} else {
Expand All @@ -146,27 +156,33 @@ export class FancytreeAdapter {

// transform the JSON response into a data structure that's supported by FancyTree
postProcess: function (event, data) {
if (null == data.error) {
var result = requestNodeToFancytreeNode(data.response);
if ("" === result.key) {
result = result.children;
} else {
result = [result];
}

if (result.length == 1) {
result[0].expanded = true;
}

data.result = result;
if (useCache) {
cache.set(data.node.getKeyPath(), result);
}
} else {
if (data.hasOwnProperty('error') && null != data.error) {
data.result = {
// todo: maybe use a more admin friendly error message in prod?
error: 'An error occured while retrieving the nodes: ' + data.error
};

return;
}

let result = requestNodeToFancytreeNode(data.response);
let nodeIsDuplicate = function (node, parentPath) {
return parentPath == node.refPath;
};

if (nodeIsDuplicate(result, data.node.data.refPath)) {
result = result.children;
} else {
result = [result];
}

if (result.length == 1 && undefined !== result[0].folder) {
result[0].expanded = true;
}

data.result = result;
if (useCache) {
cache.set(data.node.data.refPath, result);
}
},

Expand All @@ -186,44 +202,56 @@ export class FancytreeAdapter {
}

this.tree = this.$tree.fancytree('getTree');

this.tree.getNodeByRefPath = function (refPath) {
return this.findFirst((node) => {
return node.data.refPath == refPath;
});
};
}

bindToInput($input) {
var root = this.rootNode;
if (root.substr(-1) == '/') {
var root = this.rootNode.substr(0, -1);
}
var rootParent = root.substr(0, root.lastIndexOf('/'));

// output active node to input field
this.$tree.fancytree('option', 'activate', (event, data) => {
$input.val(rootParent + data.node.getKeyPath());
$input.val(data.node.data.refPath);
});

var showKey = (key) => {
this.tree.loadKeyPath(key, function (node, status) {
var showPath = (path) => {
if (!this.pathKeyMap.hasOwnProperty(path)) {
return;
}

this.tree.loadKeyPath(generateKeyPath(path), function (node, status) {
if ('ok' == status) {
node.setExpanded();
node.setActive();
}
});
};
var removeRoot = (path) => {
if (0 === path.indexOf(rootParent + '/')) {
return path.substr(rootParent.length + 1);
}
var generateKeyPath = (path) => {
var keyPath = '';
var refPath = '';
var subPaths = path.split('/');

subPaths.forEach((subPath) => {
if (subPath == '' || !this.pathKeyMap.hasOwnProperty(refPath += '/' + subPath)) {
return;
}

keyPath += '/' + this.pathKeyMap[refPath];
});

return path;
return keyPath;
};

// use initial input value as active node
this.$tree.bind('fancytreeinit', function (event, data) {
showKey(removeRoot($input.val()));
showPath($input.val());
});

// change active node when the value of the input field changed
$input.on('change', function (e) {
showKey(removeRoot($(this).val()));
showPath($(this).val());
});
}

Expand Down
2 changes: 1 addition & 1 deletion Resources/public/css/cmf_tree_browser.fancytree.css

Large diffs are not rendered by default.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 3 additions & 2 deletions Resources/public/js/cmf_tree_browser.fancytree.js

Large diffs are not rendered by default.

22 changes: 11 additions & 11 deletions Resources/public/vendor/jquery-ui/jquery-ui.min.js

Large diffs are not rendered by default.

9 changes: 4 additions & 5 deletions Resources/public/vendor/jquery/dist/jquery.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Resources/views/Base/scripts.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@
<script>window.jQuery.ui || document.write('<script src="{{ asset(assetsBasePath ~ '/jquery-ui/jquery-ui.min.js') }}"><\/script>')</script>
{% endif %}

<script src="{{ asset('bundles/cmftreebrowser/js/cmf_tree_browser.' ~ treeAdapter ~ '.js') }}" type="text/javascript"></script>
<script src="{{ asset('bundles/cmftreebrowser/js/cmf_tree_browser.' ~ treeAdapter ~ '.js?' ~ 'now'|format('u')) }}" type="text/javascript"></script>

<link rel="stylesheet" href="{{ asset('bundles/cmftreebrowser/css/cmf_tree_browser.' ~ treeAdapter ~ '.css') }}" media="all"/>
41 changes: 25 additions & 16 deletions Tests/js/adapter/fancytreeSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,9 @@ describe('The Fancytree adapter', function() {

var tree = this.$tree.fancytree('getTree');

expect(tree.getNodeByKey('cms').isExpanded()).toBe(true);
tree.init = () => {
expect(tree.getNodeByRefPath('/cms').isExpanded()).toBe(true);
}
});

it('lazy loads not yet loaded children', function () {
Expand All @@ -87,12 +89,14 @@ describe('The Fancytree adapter', function() {

var tree = this.$tree.fancytree('getTree');

tree.getNodeByKey('content').setExpanded();
tree.init = () => {
tree.getNodeByRefPath('/cms/content').setExpanded();

expect(jasmine.Ajax.requests.mostRecent().url).toMatch(/^\/api\?path=%2Fcms%2Fcontent/);
expect(jasmine.Ajax.requests.mostRecent().url).toMatch(/^\/api\?path=%2Fcms%2Fcontent/);
}
});

it('caches the nodes globally', function () {
xit('caches the nodes globally', function () {
var adapter = new FancytreeAdapter({
request: {
load: function (path) {
Expand Down Expand Up @@ -185,11 +189,13 @@ describe('The Fancytree adapter', function() {

var tree = this.$tree.fancytree('getTree');

tree.getNodeByKey('cms').setActive();
expect($input).toHaveValue('/cms');
tree.init = () => {
tree.getNodeByRefPath('/cms').setActive();
expect($input).toHaveValue('/cms');

tree.getNodeByKey('content').setActive();
expect($input).toHaveValue('/cms/content');
tree.getNodeByRefPath('/cms/content').setActive();
expect($input).toHaveValue('/cms/content');
};
});

it('updates the active node based on the value of the path ouput', function () {
Expand All @@ -198,14 +204,14 @@ describe('The Fancytree adapter', function() {
this.adapter.bindToInput($input);

var tree = this.$tree.fancytree('getTree');
// fixme: why is this not called automatically?
this.$tree.trigger('fancytreeinit');

expect(tree.getNodeByKey('content').isActive()).toBe(true);
tree.init = () => {
expect(tree.getNodeByRefPath('/cms/content').isActive()).toBe(true);

$input.val('/cms');
$input.trigger('change');
expect(tree.getNodeByKey('cms').isActive()).toBe(true);
$input.val('/cms');
$input.trigger('change');
expect(tree.getNodeByRefPath('/cms/content').isActive()).toBe(true);
}
});

it('prefixes the root node to path output when configured', function () {
Expand Down Expand Up @@ -252,8 +258,11 @@ describe('The Fancytree adapter', function() {

var tree = this.$tree.fancytree('getTree');

tree.getNodeByKey('content').setActive();
expect($input).toHaveValue('/cms/content');
tree.init = () => {
tree.getNodeByRefPath('/cms/content').setActive();

expect($input).toHaveValue('/cms/content');
}
});

});
2 changes: 1 addition & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
],
"license": "MIT",
"dependencies": {
"fancytree": "2.7.*"
"fancytree": "2.21.*"
},
"private": true,
"ignore": ["*"]
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@
}
],
"require": {
"php": "^5.3.3|^7.0",
"php": "^5.6|^7.0",
"symfony-cmf/resource-rest-bundle": "~1.0"
},
"require-dev": {
"symfony/form": "^2.8|^3.0"
},
"minimum-stability": "dev",
"minimum-stability": "RC",
"prefer-stable": true,
"autoload": {
"psr-4": {
Expand Down
Loading