Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Update jquery.select-hierarchy.js #13

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
268 changes: 138 additions & 130 deletions lib/js/jquery.select-hierarchy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,137 +3,145 @@
*
* Turns a single select containing breadcrumb trails into multiple dynamic selects to allow easy drill-down
*
* Author: Andrew Ingram (andy@andrewingram.net)
*/
(function($){
$.fn.selectHierarchy = function(options) {
var defaults = {
separator: ' > ',
hideOriginal: true,
placeholder: '------'
};
var options = $.extend(defaults, options);
var obj = $(this);
var max_depth = 1;

var choices = obj.find('option').map(function(){
var val = $(this).val();

if (val) {
var txt = $(this).text();
var segments = txt.split(options.separator);
var depth = segments.length;

if (depth > max_depth) {
max_depth = depth;
}

var result = {
label: txt,
short_label: segments[depth-1],
value: val,
depth: depth,
children: []
};

return result;
}
});

var roots = [];

// Build up child values
for (var depth=1; depth<=max_depth; depth++) {
$.each(choices, function() {
var parent = this;

if (parent.depth==depth) {
if (depth===1) {
roots.push(this);
}

$.each(choices, function() {
var child = this;
if (child.depth == depth+1 && child.label.match("^"+parent.label)==parent.label) {
parent.children.push(child);
}
});
}
});
}

if (options.hideOriginal) {
obj.hide();
}
obj.wrap('<span class="drilldown-wrapper" />');
obj.after('<select class="drilldown-1"><option value="">' + options.placeholder + '</option></select>');
var root_select = obj.next();

root_select.data('depth', 1);

$.each(roots, function(){
var opt = $('<option>');
opt.val(this.value);
opt.text(this.short_label);
opt.data('node', this);
root_select.append(opt);
});

var change_handler = function(){
var this_select = $(this);
var opt = this_select.find('option:selected');
var node = opt.data('node');

if (this_select.val()) {
obj.val(this_select.val());
} else if (this_select.data('depth') > 1) {
obj.val(this_select.prev().val());
} else {
obj.val('');
}

this_select.nextAll('select').remove();

// Check to see if there's any children, if there are we build another select box;
if (node && node.children.length > 0) {
this_select.after('<select><option value="">' + options.placeholder +'</option></select>');

var next_select = this_select.next();
next_select.addClass('drilldown-' + (node.depth + 1));
next_select.data('depth', node.depth + 1);

$.each(node.children, function(){
var opt = $('<option>');
opt.val(this.value);
opt.text(this.short_label);
opt.data('node', this);
next_select.append(opt);
});
next_select.change(change_handler);
}
}
root_select.change(change_handler);

// After setting up the behavior, set the drilldown select lists to the correct values for
// forms with a default value.

// Build an object of the choices keyed by short_label.
var choices_by_short_label = {};
$.each(choices, function() {
choices_by_short_label[(this).short_label] = (this);
});

// Break selected label into segments/short_labels
var selected_label = obj.find(' option:selected').text();
var segments = selected_label.split(options.separator);

// Loop over the segments of the selected value and select the appropriate values on the
// drilldown select lists.
var counter = 1;
$.each(segments, function() {
$('select.drilldown-' + counter, obj.parent()).val(choices_by_short_label[(this)].value);
$('select.drilldown-' + counter, obj.parent()).change();
counter++;
});
$.fn.selectHierarchy = function(options) {
this.each(function() {
var defaults = {
separator: ' > ',
hideOriginal: true,
placeholder: ''
};
var options = $.extend(defaults, options);
var obj = $(this);
var max_depth = 1;

var choices = obj.find('option').map(function(){
var val = $(this).val();

if (val) {
var txt = $(this).text();
var segments = txt.split(options.separator);
var depth = segments.length;

if (depth > max_depth) {
max_depth = depth;
}

var result = {
label: txt,
short_label: segments[depth-1],
value: val,
depth: depth,
children: []
};

return result;
}
});

var roots = [];

// Build up child values
for (var depth=1; depth<=max_depth; depth++) {
$.each(choices, function() {
var parent = this;

if (parent.depth==depth) {
if (depth===1) {
roots.push(this);
}

$.each(choices, function() {
var child = this;
if (child.depth == depth+1 && child.label.match("^"+parent.label)==parent.label) {
parent.children.push(child);
}
});
}
});
}

if (options.hideOriginal) {
obj.hide();
}
obj.wrap('<span class="drilldown-wrapper chain-selects" />');
obj.after('<select class="drilldown-1 form-control"><option value="">' + options.placeholder + '</option></select>');
var root_select = obj.next();

root_select.data('depth', 1);

$.each(roots, function(){
var opt = $('<option>');
opt.val(this.value);
opt.text(this.short_label);
opt.data('node', this);
root_select.append(opt);
});

var change_handler = function(){
var this_select = $(this);
var opt = this_select.find('option:selected');
var node = opt.data('node');

if (this_select.val()) {
obj.val(this_select.val());
} else if (this_select.data('depth') > 1) {
obj.val(this_select.prevAll('select').first().val());
} else {
obj.val('');
}

this_select.nextAll().remove();

// Check to see if there's any children, if there are we build another select box;
if (node && node.children.length > 0) {
this_select.after('<span class="glyphicon glyphicon-chevron-right"></span><select><option value="">' + options.placeholder +'</option></select>');

var next_select = this_select.nextAll('select').first();
next_select.addClass('drilldown-' + (node.depth + 1));
next_select.addClass('form-control');
next_select.data('depth', node.depth + 1);

$.each(node.children, function(){
var opt = $('<option>');
opt.val(this.value);
opt.text(this.short_label);
opt.data('node', this);
next_select.append(opt);
});
next_select.change(change_handler);
}
}
root_select.change(change_handler);

// After setting up the behavior, set the drilldown select lists to the correct values for
// forms with a default value.

// Build an object of the choices keyed by short_label.
var choices_by_label = {};
$.each(choices, function() {
choices_by_label[(this).label] = (this);
});


// Break selected label into segments/short_labels
var selected_label = obj.find(' option:selected').text();
var segments = selected_label != '' ? selected_label.split(options.separator) : [];

var labels = [];
for (var i in segments) {
labels.push(segments.slice(0, parseInt(i)+1).join(options.separator));
}

// Loop over the segments of the selected value and select the appropriate values on the
// drilldown select lists.
var counter = 1;
$.each(labels, function() {
$('select.drilldown-' + counter, obj.parent()).val(choices_by_label[(this)].value);
$('select.drilldown-' + counter, obj.parent()).change();
counter++;
});
});
};
})(jQuery);