Skip to content
This repository has been archived by the owner on Feb 12, 2022. It is now read-only.

Do not change tree folder icons when selecting items for 3.7.x branch #1312

Merged
merged 3 commits into from
May 22, 2015
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: 2 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,8 @@ <h3>only items selectable (please note structure of treebranch)</h3>

</div>
<div class="btn-panel">
<button type="button" class="btn btn-default" id="btnTreeDestroy">destroy and append</button>
<button type="button" class="btn btn-default" id="btnTreeDestroy">destroy and append</button>
<button type="button" class="btn btn-default" id="btnTreeClearSelected">clear all selected</button>
<button type="button" class="btn btn-default" id="btnTreeDiscloseVisible">disclose visible</button>
<button type="button" class="btn btn-default" id="btnTreeDiscloseAll">disclose all</button>
<button type="button" class="btn btn-default" id="btnTreeCloseAll">close all</button>
Expand Down
4 changes: 4 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -992,6 +992,10 @@ myTreeInit();
myTreeInit();
});

$('#btnTreeClearSelected').click(function () {
log('Items/folders cleared: ', $('#myTree1').tree('deselectAll') );
});

$('#btnTreeDiscloseVisible').click(function () {
$('#myTree1').tree('discloseVisible');
});
Expand Down
198 changes: 108 additions & 90 deletions js/tree.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@
Tree.prototype = {
constructor: Tree,

deselectAll: function deselectAll(nodes) {
// clear all child tree nodes and style as deselected
nodes = nodes || this.$element;
var $selectedElements = $(nodes).find('.tree-selected');
$selectedElements.each(function (index, element) {
styleNodeDeselected( $(element), $(element).find( '.glyphicon' ) );
});
return $selectedElements;
},

destroy: function destroy() {
// any external bindings [none]
// empty elements to return to original markup
Expand Down Expand Up @@ -159,59 +169,43 @@
});
},

selectItem: function selectItem(el) {
if (!this.options.itemSelect) return;
var $el = $(el);
var selData = $el.data();
var $all = this.$element.find('.tree-selected');
var data = [];
var $icon = $el.find('.icon-item');

if (this.options.multiSelect) {
$.each($all, function (index, value) {
var $val = $(value);
if ($val[0] !== $el[0]) {
data.push($(value).data());
}
});
} else if ($all[0] !== $el[0]) {
$all.removeClass('tree-selected')
.find('.glyphicon').removeClass('glyphicon-ok').addClass('fueluxicon-bullet');
data.push(selData);
}

var eventType = 'selected';
if ($el.hasClass('tree-selected')) {
eventType = 'deselected';
$el.removeClass('tree-selected');
if ($icon.hasClass('glyphicon-ok') || $icon.hasClass('fueluxicon-bullet')) {
$icon.removeClass('glyphicon-ok').addClass('fueluxicon-bullet');
}

} else {
$el.addClass ('tree-selected');
// add tree dot back in
if ($icon.hasClass('glyphicon-ok') || $icon.hasClass('fueluxicon-bullet')) {
$icon.removeClass('fueluxicon-bullet').addClass('glyphicon-ok');
}
selectTreeNode: function selectItem(clickedElement, nodeType) {
var clicked = {}; // object for clicked element
clicked.$element = $(clickedElement);

if (this.options.multiSelect) {
data.push(selData);
}
var selected = {}; // object for selected elements
selected.$elements = this.$element.find('.tree-selected');
selected.dataForEvent = [];

// determine clicked element and it's icon
if (nodeType === 'folder') {
// make the clicked.$element the container branch
clicked.$element = clicked.$element.closest('.tree-branch');
clicked.$icon = clicked.$element.find('.icon-folder');
}
else {
clicked.$icon = clicked.$element.find('.icon-item');
}
clicked.elementData = clicked.$element.data();

this.$element.trigger(eventType + '.fu.tree', {
target: selData,
selected: data
// the below functions pass objects by copy/reference and use modified object in this function
if ( this.options.multiSelect ) {
multiSelectSyncNodes(this, clicked, selected);
}
else {
singleSelectSyncNodes(this, clicked, selected);
}

// all done with the DOM, now fire events
this.$element.trigger(selected.eventType + '.fu.tree', {
target: clicked.elementData,
selected: selected.dataForEvent
});

// Return new list of selected items, the item
// clicked, and the type of event:
$el.trigger('updated.fu.tree', {
selected: data,
item: $el,
eventType: eventType
clicked.$element.trigger('updated.fu.tree', {
selected: selected.dataForEvent,
item: clicked.$element,
eventType: selected.eventType
});
},

Expand Down Expand Up @@ -270,52 +264,16 @@
}
},

selectFolder: function selectFolder(clickedElement) {
if (!this.options.folderSelect) return;
var $clickedElement = $(clickedElement);
var $clickedBranch = $clickedElement.closest('.tree-branch');
var $selectedBranch = this.$element.find('.tree-branch.tree-selected');
var clickedData = $clickedBranch.data();
var selectedData = [];
var eventType = 'selected';

// select clicked item
if ($clickedBranch.hasClass('tree-selected')) {
eventType = 'deselected';
$clickedBranch.removeClass('tree-selected');
} else {
$clickedBranch.addClass('tree-selected');
selectFolder: function selectFolder(el) {
if (this.options.folderSelect) {
this.selectTreeNode(el, 'folder');
}
},

if (this.options.multiSelect) {
// get currently selected
$selectedBranch = this.$element.find('.tree-branch.tree-selected');

$.each($selectedBranch, function (index, value) {
var $value = $(value);
if ($value[0] !== $clickedElement[0]) {
selectedData.push($(value).data());
}
});

} else if ($selectedBranch[0] !== $clickedElement[0]) {
$selectedBranch.removeClass('tree-selected');

selectedData.push(clickedData);
selectItem: function selectItem(el) {
if (this.options.itemSelect) {
this.selectTreeNode(el, 'item');
}

this.$element.trigger(eventType + '.fu.tree', {
target: clickedData,
selected: selectedData
});

// Return new list of selected items, the item
// clicked, and the type of event:
$clickedElement.trigger('updated.fu.tree', {
selected: selectedData,
item: $clickedElement,
eventType: eventType
});
},

selectedItems: function selectedItems() {
Expand Down Expand Up @@ -465,11 +423,71 @@
}
};


// ALIASES

//alias for collapse for consistency. "Collapse" is an ambiguous term (collapse what? All? One specific branch?)
Tree.prototype.closeAll = Tree.prototype.collapse;
//alias for backwards compatibility because there's no reason not to.
Tree.prototype.openFolder = Tree.prototype.discloseFolder;


// PRIVATE FUNCTIONS

function styleNodeSelected ($element, $icon) {
$element.addClass('tree-selected');
if ( $element.data('type') === 'item' && $icon.hasClass('fueluxicon-bullet') ) {
$icon.removeClass('fueluxicon-bullet').addClass('glyphicon-ok'); // make checkmark
}
}

function styleNodeDeselected ($element, $icon) {
$element.removeClass('tree-selected');
if ( $element.data('type') === 'item' && $icon.hasClass('glyphicon-ok') ) {
$icon.removeClass('glyphicon-ok').addClass('fueluxicon-bullet'); // make bullet
}
}

function multiSelectSyncNodes (self, clicked, selected) {
// search for currently selected and add to selected data list if needed
$.each(selected.$elements, function (index, element) {
var $element = $(element);
if ($element[0] !== clicked.$element[0]) {
selected.dataForEvent.push( $($element).data() );
}
});

if (clicked.$element.hasClass('tree-selected')) {
styleNodeDeselected (clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'deselected';
}
else {
styleNodeSelected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'selected';
selected.dataForEvent.push(clicked.elementData);
}
}

function singleSelectSyncNodes(self, clicked, selected) {
// element is not currently selected
if (selected.$elements[0] !== clicked.$element[0]) {
var clearedElements = self.deselectAll(self.$element);
styleNodeSelected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'selected';
selected.dataForEvent = [clicked.elementData];
}
else {
styleNodeDeselected(clicked.$element, clicked.$icon);
// set event data
selected.eventType = 'deselected';
selected.dataForEvent = [];
}
}


// TREE PLUGIN DEFINITION

$.fn.tree = function tree(option) {
Expand Down
7 changes: 7 additions & 0 deletions test/markup/tree-markup.html
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@
<ul class="tree-branch-children"></ul>
<div class="tree-loader" role="alert">Loading...</div>
</li>
<!-- item template -->
<li class="tree-item hidden" data-template="treeitem" role="treeitem">
<button class="tree-item-name">
<span class="glyphicon icon-item fueluxicon-bullet"></span>
<span class="tree-label">Example Item</span>
</button>
</li>
</ul>

</div>
Expand Down
25 changes: 20 additions & 5 deletions test/tree-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,12 +182,13 @@ define(function (require) {

$selNode = $tree.find('.tree-branch:eq(1)');
$tree.tree('discloseFolder', $selNode.find('.tree-branch-header'));
equal($selNode.find('.tree-branch-children > li').length, 4, 'Folder has been populated with sub-folders');
equal($selNode.find('.tree-branch-children > li').length, 8, 'Folder has been populated with sub-folders and items');
});

test("Single item/folder selection works as designed", function () {
var $tree = $(html).find('#MyTree');

// multiSelect: false is the default
$tree.tree({
dataSource: this.dataSource
});
Expand All @@ -204,10 +205,24 @@ define(function (require) {
folderSelect: true
});

$tree.tree('selectItem', $tree.find('.tree-branch-name:eq(1)'));
equal($tree.tree('selectedItems').length, 1, 'Return single selected value');
$tree.tree('selectItem', $tree.find('.tree-branch-name:eq(2)'));
equal($tree.tree('selectedItems').length, 1, 'Return new single selected value');
$tree.tree('selectItem', $tree.find('.tree-item:eq(1)'));
equal($tree.tree('selectedItems').length, 1, 'Return single selected item (none previously selected, 1st programatic selection)');

$tree.tree('selectFolder', $tree.find('.tree-branch-name:eq(1)'));
equal($tree.tree('selectedItems').length, 1, 'Return single selected folder (item previously selected, 2nd programatic selection)');

$tree.tree('selectItem', $tree.find('.tree-item:eq(2)'));
equal($tree.tree('selectedItems').length, 1, 'Return single selected item (folder previously selected, 3rd programatic selection)');

$tree.find('.tree-item:eq(1)').click();
equal($tree.tree('selectedItems').length, 1, 'Return single selected item (item previously selected, 1st click selection)');

$tree.find('.tree-branch-name:eq(1)').click();
equal($tree.tree('selectedItems').length, 1, 'Return single selected folder (item previously selected, 2nd click selection)');

$tree.find('.tree-item:eq(2)').click();
equal($tree.tree('selectedItems').length, 1, 'Return single selected item (folder previously selected, 3rd click selection)');

});

test("Multiple item/folder selection works as designed", function () {
Expand Down