Skip to content

Commit

Permalink
Add paging to full-width treeview, refs #12611
Browse files Browse the repository at this point in the history
Add pagination to full-width treeview, sharing code with the hierarchy
browser, so large collections don't incur a large performance hit
when displaying.
  • Loading branch information
mcantelon committed Dec 5, 2018
1 parent fa3915a commit 8306556
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 110 deletions.
1 change: 1 addition & 0 deletions apps/qubit/modules/browse/config/view.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ hierarchySuccess:
/vendor/jstree/jstree.min.js:
treeviewTypes:
pager:
treeViewPager:
hierarchy:
23 changes: 18 additions & 5 deletions apps/qubit/modules/default/actions/fullTreeViewAction.class.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ protected function getNodeOrChildrenNodes($id, $baseReferenceCode, $children = f
// Determine ordering
$orderColumn = (isset($options['orderColumn'])) ? $options['orderColumn'] : 'io.lft';

// Assemble LIMIT clause, if applicable
// If we're currently fetching children and paging options are set,
// use paging options to assemble LIMIT clause
$limitClause = "";
$skip = (isset($options['skip'])) ? $options['skip'] : null;
$limit = (isset($options['limit'])) ? $options['limit'] : null;
if (ctype_digit($skip) || ctype_digit($limit))

if ($children && (ctype_digit($skip) || ctype_digit($limit)))
{
$limitClause = "LIMIT ";
$limitClause .= (ctype_digit($skip)) ? $skip : "0";
Expand Down Expand Up @@ -224,12 +226,13 @@ protected function getNodeOrChildrenNodes($id, $baseReferenceCode, $children = f
$result['a_attr']['title'] = strip_tags($result['text']);
$result['a_attr']['href'] = $this->generateUrl('slug', array('slug' => $result['slug']));

// Set children to true for lazy loading or, if we are loading
// an ancestor of the resource or the resource, load all children
// If not a leaf node, indicate node has children
if ($result['rgt'] - $result['lft'] > 1)
{
// Set children to default of true for lazy loading
$result['children'] = true;

// If loading an ancestor of the resource, fetch children
if ($result['lft'] <= $this->resource->lft && $result['rgt'] >= $this->resource->rgt)
{
$refCode = '';
Expand All @@ -238,8 +241,18 @@ protected function getNodeOrChildrenNodes($id, $baseReferenceCode, $children = f
$refCode = $result['referenceCode'];
}

$childData = $this->getNodeOrChildrenNodes($result['id'], $refCode, $children = true);
// If we're not currently fetching children and paging options are set,
// use paging options when fetching children
$childOptions = array();
if (!$children && (isset($options['skip']) || isset($options['limit'])))
{
$childOptions = array('skip' => $options['skip'], 'limit' => $options['limit']);
}

// Fetch children and note total number of children that exist (useful for paging through children)
$childData = $this->getNodeOrChildrenNodes($result['id'], $refCode, $children = true, $childOptions);
$result['children'] = $childData['nodes'];
$result['total'] = $childData['total'];
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,20 @@ public function execute($request)
QubitAcl::forwardUnauthorized();
}

// Impose limit to what nodeLimit parameter can be set to
if (!ctype_digit($request->nodeLimit) || $request->nodeLimit > 1000)
{
$request->nodeLimit = 1000;
}

$baseReferenceCode = '';

// Allow the ability to page through children
$options = array(
'skip' => $request->skip,
'limit' => $request->nodeLimit
);

// On first load, retrieve the ancestors of the selected resource, the resource
// and its children, otherwise get only the resource's children
if (filter_var($request->getParameter('firstLoad', false), FILTER_VALIDATE_BOOLEAN)
Expand All @@ -57,7 +69,7 @@ public function execute($request)
$baseReferenceCode = render_value_inline($collectionRoot->getInheritedReferenceCode());
}

$data = $this->getNodeOrChildrenNodes($collectionRoot->id, $baseReferenceCode);
$data = $this->getNodeOrChildrenNodes($collectionRoot->id, $baseReferenceCode, $children = false, $options);
}
else
{
Expand All @@ -72,9 +84,9 @@ public function execute($request)
}
}

$data = $this->getNodeOrChildrenNodes($this->resource->id, $baseReferenceCode, $children = true);
$data = $this->getNodeOrChildrenNodes($this->resource->id, $baseReferenceCode, $children = true, $options);
}

return $this->renderText(json_encode($data['nodes']));
return $this->renderText(json_encode($data));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,8 @@ public function execute($request)
$this->getResponse()->addStylesheet('fullWidthTreeView', 'last');
$this->getResponse()->addStylesheet('/vendor/jstree/themes/default/style.min.css', 'last');
$this->getResponse()->addJavascript('treeviewTypes', 'last');
$this->getResponse()->addJavascript('pager', 'last');
$this->getResponse()->addJavascript('treeViewPager', 'last');
$this->getResponse()->addJavascript('fullWidthTreeView', 'last');
$this->getResponse()->addJavascript('/vendor/jstree/jstree.min.js', 'last');
}
Expand Down
3 changes: 3 additions & 0 deletions apps/qubit/modules/informationobject/templates/_actions.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,7 @@

</ul>

<input type="button" id="fullwidth-treeview-reset-button" class="c-btn c-btn-submit" value="<?php echo __('Reset') ?>" />
<input type="button" id="fullwidth-treeview-more-button" class="c-btn c-btn-submit" data-label="<?php echo __('%1% more') ?>" value="" />
<span id="fullwidth-treeview-collection-url" data-collection-url="<?php echo url_for(array($resource->getCollectionRoot(), 'module' => 'informationobject')) ?>"></span>
</section>
4 changes: 2 additions & 2 deletions css/fullWidthTreeView.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@
text-overflow: ellipsis;
}

.hierarchy > .container > input[type="button"] {
.hierarchy > .container > input[type="button"], #main-column > input[type="button"] {
margin-top: 14px;
margin-left: 6px;
float: right;
}

#fullwidth-treeview-more-button {
display: none;
margin-right: 6px;
}

#fullwidth-treeview-activity-indicator {
Expand Down
83 changes: 62 additions & 21 deletions js/fullWidthTreeView.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,19 @@
(function ($) {
"use strict";

// Handle older browser using hash/anchor urls
if (window.location.hash)
{
var url = window.location.hash.match("\/([^?]*)");
if (url[1].length)
{
window.location = url[1];
return;
}
}

"use strict";
(function ($) {

$(loadTreeView);

function loadTreeView ()
{
var url = '/informationobject/fullWidthTreeView';
var collectionUrl = $('#fullwidth-treeview-collection-url').data('collection-url');
var pathToApi = '/informationobject/fullWidthTreeView';
var $fwTreeView = $('<div id="fullwidth-treeview"></div>');
var $fwTreeViewRow = $('<div id="fullwidth-treeview-row"></div>');
var $mainHeader = $('#main-column h1').first();
var $mainHeader = $('#main-column h1');
var $moreButton = $('#fullwidth-treeview-more-button');
var $resetButton = $('#fullwidth-treeview-reset-button');
var pager = new Qubit.TreeviewPager(50, $fwTreeView, collectionUrl + pathToApi);

// Add tree-view divs after main header, animate and allow resize
$mainHeader.after(
Expand All @@ -30,6 +23,9 @@
.resizable({handles: 's'})
);

$mainHeader.before($resetButton);
$mainHeader.before($moreButton);

// Declare jsTree options
var options = {
'plugins': ['types', 'dnd'],
Expand All @@ -50,24 +46,52 @@
'core': {
'data': {
'url': function (node) {
// Get results
var queryString = "?nodeLimit=" + (pager.getSkip() + pager.getLimit());

return node.id === '#' ?
window.location.pathname.match("^[^;]*")[0] + url :
window.location.pathname.match("^[^;]*")[0] + pathToApi + queryString :
node.a_attr.href + url;
},
'data': function (node) {
return node.id === '#' ?
{'firstLoad': true} :
{'firstLoad': false, 'referenceCode': node.original.referenceCode};
}
},

'dataFilter': function (response) {
// Data from the initial request for hierarchy data contains
// additional data relating to paging so we need to parse to
// differentiate it.
var data = JSON.parse(response);

// Note root node's href and set number of available items to page through
if (pager.rootId == '#')
{
pager.rootId = data.nodes[0].id;
pager.setTotal(data.nodes[0].total);
}

// Allow for both styles of nodes
if (typeof data.nodes === "undefined") {
// Data is an array of jsTree node definitions
return JSON.stringify(data);
} else {
// Data includes both nodes and the total number of available nodes
return JSON.stringify(data.nodes);
}
},
},
'check_callback': function (operation, node, node_parent, node_position, more) {
// Operations allowed:
// - Before and after drag and drop between siblings
// - Move core operations (node drop event)
return operation === 'move_node'
&& (more.core || (more.dnd
&& node.parent === more.ref.parent
&& more.pos !== 'i'));
return operation === 'create_node' ||
(operation === 'move_node'
&& (more.core || (more.dnd
&& node.parent === more.ref.parent
&& more.pos !== 'i'))
);
}
}
};
Expand All @@ -82,6 +106,8 @@
$activeNode.scrollIntoView(true);
$('body')[0].scrollIntoView(true);
}

pager.updateMoreLink($moreButton, $resetButton);
};

// On node selection: load the informationobject's page and insert the current page
Expand Down Expand Up @@ -195,6 +221,21 @@
.bind('open_node.jstree', openNodeListener)
.bind('move_node.jstree', moveNodeListener);

// Clicking "more" will add next page of results to tree
$moreButton.click(function() {
pager.next();
pager.getAndAppendNodes(function() {
// Queue is empty so update paging link
pager.updateMoreLink($moreButton, $resetButton);
});
});

// Clicking reset link will reset paging and tree state
$('#fullwidth-treeview-reset-button').click(function()
{
pager.reset($moreButton, $resetButton);
});

// TODO restore window.history states
$(window).bind('popstate', function() {});
}
Expand Down
Loading

0 comments on commit 8306556

Please sign in to comment.