Skip to content

Commit

Permalink
make class picker respect language path changes
Browse files Browse the repository at this point in the history
  • Loading branch information
smurp committed Sep 18, 2018
1 parent 8060dc9 commit 8d946b8
Show file tree
Hide file tree
Showing 4 changed files with 199 additions and 33 deletions.
135 changes: 118 additions & 17 deletions lib/huviz.js
Original file line number Diff line number Diff line change
Expand Up @@ -2265,14 +2265,21 @@ OnceRunner.prototype.makeWrapper = function(callback) {
return this.recolor_edges();
};

CommandController.prototype.resort_pickers = function() {
var _ref;
if ((_ref = this.taxon_picker) != null) {
_ref.resort_recursively();
}
};

CommandController.prototype.build_predicate_picker = function(label) {
var id, title, where;
var extra_classes, id, needs_expander, sort_by_label, squash_case, title, where;
id = 'predicates';
title = "Medium color: all edges shown -- click to show none\n" + "Faint color: no edges are shown -- click to show all\n" + "Stripey color: some edges shown -- click to show all\n" + "Hidden: no edges among the selected nodes";
where = (label != null) && this.control_label(label, this.comdiv, title) || this.comdiv;
this.predicatebox = where.append('div').classed('container', true).attr('id', id);
this.predicates_ignored = [];
this.predicate_picker = new ColoredTreePicker(this.predicatebox, 'anything', [], true);
this.predicate_picker = new ColoredTreePicker(this.predicatebox, 'anything', (extra_classes = []), (needs_expander = true), (sort_by_label = true), (squash_case = true));
this.predicate_hierarchy = {
'anything': ['anything']
};
Expand Down Expand Up @@ -2337,13 +2344,13 @@ OnceRunner.prototype.makeWrapper = function(callback) {
};

CommandController.prototype.build_taxon_picker = function(label, where) {
var id, title;
var extra_classes, id, needs_expander, sort_by_label, squash_case, title;
id = 'classes';
title = "Medium color: all nodes are selected -- click to select none\n" + "Faint color: no nodes are selected -- click to select all\n" + "Stripey color: some nodes are selected -- click to select all\n";
where = (label != null) && this.control_label(label, where, title) || this.comdiv;
this.taxon_box = where.append('div').classed('container', true).attr('id', id);
this.taxon_box.attr('style', 'vertical-align:top');
this.taxon_picker = new ColoredTreePicker(this.taxon_box, 'Thing', [], true);
this.taxon_picker = new ColoredTreePicker(this.taxon_box, 'Thing', (extra_classes = []), (needs_expander = true), (sort_by_label = true), (squash_case = true));
this.taxon_picker.click_listener = this.on_taxon_clicked;
this.taxon_picker.hover_listener = this.on_taxon_hovered;
this.taxon_picker.show_tree(this.hierarchy, this.taxon_box);
Expand Down Expand Up @@ -8835,7 +8842,7 @@ OnceRunner.prototype.makeWrapper = function(callback) {
};

Huviz.prototype.on_change_language_path = function(new_val, old_val) {
var e;
var e, _ref;
try {
MultiString.set_langpath(new_val);
} catch (_error) {
Expand All @@ -8846,7 +8853,10 @@ OnceRunner.prototype.makeWrapper = function(callback) {
}
if (this.shelved_set) {
this.shelved_set.resort();
return this.discarded_set.resort();
this.discarded_set.resort();
}
if ((_ref = this.gclui) != null) {
_ref.resort_pickers();
}
};

Expand Down Expand Up @@ -10816,6 +10826,15 @@ Build and control a hierarchic menu of arbitrarily nested divs looking like:
* On the other hand, branches in the tree which are empty are hidden.
* Clicking uncollapsed branches cycles just their selectedness.
* Clicking collapsed branches cycles the selectedness of them and their children.
* <div class="container"> a container holds one or more contents
* <div class="contents"> a content (ie a node such as THING) may have a container for it kids
* so the CONTENT with id=Thing is within the root CONTAINER
and the Thing CONTENT itself holds a CONTAINER with the child CONTENTS of its subclasses
Possible Bug: it appears that <div class="container" id="classes"> has a redundant child
which looks like <div class="container">.
It is unclear why this is needed. Containers should not directly hold containers.
*/

(function() {
Expand All @@ -10825,34 +10844,43 @@ Build and control a hierarchic menu of arbitrarily nested divs looking like:
uniquer = require("uniquer").uniquer;

TreePicker = (function() {
function TreePicker(elem, root, extra_classes, needs_expander) {
function TreePicker(elem, root, extra_classes, needs_expander, sort_by_label) {
this.elem = elem;
this.needs_expander = needs_expander;
this.sort_by_label = sort_by_label;
this.onChangeState = __bind(this.onChangeState, this);
this.handle_click = __bind(this.handle_click, this);
this.click_handler = __bind(this.click_handler, this);
if (extra_classes != null) {
this.extra_classes = extra_classes;
}
this.id_to_elem = {
root: elem
};
this.id_to_elem[root] = elem;
if (this.sort_by_label == null) {
this.sort_by_label = true;
}
if (this.squash_case_during_sort == null) {
this.squash_case_during_sort = true;
}
this.id_to_elem = {};
this.id_to_elem['/'] = elem;
this.ids_in_arrival_order = [root];
this.id_is_abstract = {};
this.id_is_collapsed = {};
this.id_to_state = {
"true": {},
"false": {}
};
this.id_to_parent = {};
this.id_to_children = {};
this.id_to_parent = {
root: '/'
};
this.id_to_children = {
'/': [root]
};
this.id_to_payload_collapsed = {};
this.id_to_payload_expanded = {};
this.id_to_name = {};
this.set_abstract(root);
this.set_abstract('/');
this.set_abstract('root');
console.log('shield', this.shield);
}

TreePicker.prototype.get_my_id = function() {
Expand Down Expand Up @@ -10901,15 +10929,88 @@ Build and control a hierarchic menu of arbitrarily nested divs looking like:
return uniquer(uri);
};

TreePicker.prototype.get_childrens_ids = function(parent_id) {
if (parent_id == null) {
parent_id = '/';
}
return this.id_to_children[parent_id] || [];
};

TreePicker.prototype.get_container_elem_within_id = function(an_id) {
var content_elem;
content_elem = this.id_to_elem[an_id][0][0];
return content_elem.querySelector('.container');
};

TreePicker.prototype.resort_recursively = function(an_id) {
var child_elem, child_id, container_elem, elem, kids_ids, sort_by_first_item, val, val_elem, val_elem_pairs, _i, _j, _len, _len1, _results;
if (an_id == null) {
an_id = '/';
}
kids_ids = this.get_childrens_ids(an_id);
if (!kids_ids || !kids_ids.length) {
return;
}
val_elem_pairs = [];
sort_by_first_item = function(a, b) {
return a[0].localeCompare(b[0]);
};
for (_i = 0, _len = kids_ids.length; _i < _len; _i++) {
child_id = kids_ids[_i];
this.resort_recursively(child_id);
val = this.get_comparison_value(child_id, this.id_to_name[child_id]);
child_elem = this.id_to_elem[child_id][0][0];
this.update_label_for_node(child_id, child_elem);
val_elem_pairs.push([val, child_elem]);
}
val_elem_pairs.sort(sort_by_first_item);
container_elem = this.get_container_elem_within_id(an_id);
if (!container_elem) {
throw "no container_elem";
}
_results = [];
for (_j = 0, _len1 = val_elem_pairs.length; _j < _len1; _j++) {
val_elem = val_elem_pairs[_j];
elem = val_elem[1];
_results.push(container_elem.appendChild(elem));
}
return _results;
};

TreePicker.prototype.update_label_for_node = function(node_id, node_elem) {
var label_elem;
if (node_elem == null) {
node_elem = this.id_to_elem[node_id];
}
label_elem = node_elem.querySelector('p.treepicker-label');
if (label_elem != null) {
return label_elem.textContent = this.id_to_name[node_id];
}
};

TreePicker.prototype.get_comparison_value = function(node_id, label) {
var this_term;
if (this.sort_by_name) {
this_term = label || node_id;
} else {
this_term = node_id;
}
if (this.squash_case_during_sort === true) {
this_term = this_term.toLowerCase();
}
return this_term;
};

TreePicker.prototype.add_alphabetically = function(i_am_in, node_id, label) {
var container, elem, elem_lower, label_lower, _i, _len, _ref;
var container, elem, label_lower, other_term, this_term, _i, _len, _ref;
label_lower = label.toLowerCase();
container = i_am_in[0][0];
this_term = this.get_comparison_value(node_id, label);
_ref = container.children;
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
elem = _ref[_i];
elem_lower = (this.id_to_name[elem.id] || elem.id).toLowerCase();
if (elem_lower > label_lower) {
other_term = this.get_comparison_value(elem.id, this.id_to_name[elem.id]);
if (other_term > this_term) {
return this.add_to_elem_before(i_am_in, node_id, "#" + elem.id, label);
}
}
Expand Down
9 changes: 7 additions & 2 deletions src/gclui.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,11 @@ class CommandController
recolor_edges_and_predicates: (evt) =>
@predicate_picker.recolor_now()
@recolor_edges() # FIXME should only really be run after the predicate set has settled for some amount of time
resort_pickers: ->
@taxon_picker?.resort_recursively()
#@predicate_picker?.resort_recursively()
#@set_picker?.resort_recursively()
return
build_predicate_picker: (label) ->
id = 'predicates'
title =
Expand All @@ -167,7 +172,7 @@ class CommandController
@predicatebox = where.append('div').classed('container',true).attr('id',id)
#@predicatebox.attr('class','scrolling')
@predicates_ignored = []
@predicate_picker = new ColoredTreePicker(@predicatebox,'anything',[],true)
@predicate_picker = new ColoredTreePicker(@predicatebox,'anything',(extra_classes=[]), (needs_expander=true), (sort_by_label=true), (squash_case=true))
@predicate_hierarchy = {'anything':['anything']}
# FIXME Why is show_tree being called four times per node?
@predicate_picker.click_listener = @on_predicate_clicked
Expand Down Expand Up @@ -213,7 +218,7 @@ class CommandController
.attr('id',id)
@taxon_box.attr('style','vertical-align:top')
# http://en.wikipedia.org/wiki/Taxon
@taxon_picker = new ColoredTreePicker(@taxon_box,'Thing',[],true)
@taxon_picker = new ColoredTreePicker(@taxon_box,'Thing', (extra_classes=[]), (needs_expander=true), (sort_by_label=true), (squash_case=true))
@taxon_picker.click_listener = @on_taxon_clicked
@taxon_picker.hover_listener = @on_taxon_hovered
@taxon_picker.show_tree(@hierarchy,@taxon_box)
Expand Down
2 changes: 2 additions & 0 deletions src/huviz.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4090,6 +4090,8 @@ class Huviz
if @shelved_set
@shelved_set.resort()
@discarded_set.resort()
@gclui?.resort_pickers()
return

on_change_color_nodes_as_pies: (new_val, old_val) -> # TODO why this == window ??
@color_nodes_as_pies = new_val
Expand Down
86 changes: 72 additions & 14 deletions src/treepicker.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,43 @@ Build and control a hierarchic menu of arbitrarily nested divs looking like:
* On the other hand, branches in the tree which are empty are hidden.
* Clicking uncollapsed branches cycles just their selectedness.
* Clicking collapsed branches cycles the selectedness of them and their children.
* <div class="container"> a container holds one or more contents
* <div class="contents"> a content (ie a node such as THING) may have a container for it kids
* so the CONTENT with id=Thing is within the root CONTAINER
and the Thing CONTENT itself holds a CONTAINER with the child CONTENTS of its subclasses
Possible Bug: it appears that <div class="container" id="classes"> has a redundant child
which looks like <div class="container">.
It is unclear why this is needed. Containers should not directly hold containers.
###

uniquer = require("uniquer").uniquer

class TreePicker
constructor: (@elem, root, extra_classes, @needs_expander) ->
constructor: (@elem, root, extra_classes, @needs_expander, @sort_by_label) ->
if extra_classes?
@extra_classes = extra_classes
@id_to_elem = {root:elem} # FIXME remove root
@id_to_elem[root] = elem
if not @sort_by_label?
@sort_by_label = true
if not @squash_case_during_sort?
@squash_case_during_sort = true
@id_to_elem = {}
@id_to_elem['/'] = elem
@ids_in_arrival_order = [root]
@id_is_abstract = {}
@id_is_collapsed = {}
@id_to_state =
true: {}
false: {}
@id_to_parent = {}
@id_to_children = {}
@id_to_parent = {root: '/'}
@id_to_children = {'/': [root]}
@id_to_payload_collapsed = {}
@id_to_payload_expanded = {}
@id_to_name = {}
@set_abstract(root)
@set_abstract(root) # FIXME is this needed?
@set_abstract('/')
@set_abstract('root') # FIXME duplication?!?
#
#@shield.classed('shield')
console.log('shield', @shield)
#debugger
get_my_id: () ->
@elem.attr("id")
shield: ->
Expand All @@ -65,30 +75,78 @@ class TreePicker
@id_is_abstract[id] = true
get_abstract_count: ->
return Object.keys(@id_is_abstract).length
is_abstract: (id) ->
is_abstract: (id) -> # ie class has no direct instances but maybe subclasses
tmp = @id_is_abstract[id]
tmp? and tmp
uri_to_js_id: (uri) ->
uniquer(uri)
get_childrens_ids: (parent_id) ->
parent_id ?= '/' # if no parent indicated, return root's kids
return @id_to_children[parent_id] or []
get_container_elem_within_id: (an_id) ->
# the div with class='container' holding class='contents' divs
content_elem = @id_to_elem[an_id][0][0]
return content_elem.querySelector('.container')
resort_recursively: (an_id) ->
an_id ?= '/' # if an_id not provided, then sort the root
kids_ids = @get_childrens_ids(an_id)
if not kids_ids or not kids_ids.length
return
val_elem_pairs = []
sort_by_first_item = (a, b) ->
return a[0].localeCompare(b[0])
for child_id in kids_ids
@resort_recursively(child_id)
val = @get_comparison_value(child_id, @id_to_name[child_id])
child_elem = @id_to_elem[child_id][0][0]
@update_label_for_node(child_id, child_elem)
val_elem_pairs.push([val, child_elem])
val_elem_pairs.sort(sort_by_first_item)
container_elem = @get_container_elem_within_id(an_id)
if not container_elem
throw "no container_elem"
for val_elem in val_elem_pairs
elem = val_elem[1]
container_elem.appendChild(elem)
update_label_for_node: (node_id, node_elem) -> # passing node_elem is optional
# This takes the current value of @id_to_name[node_id] and displays it in the HTML.
# Why? Because the label might be a MultiString whose language might have changed.
node_elem ?= @id_to_elem[node_id] # look up node_elem if it is not passed in
label_elem = node_elem.querySelector('p.treepicker-label')
if label_elem?
label_elem.textContent = @id_to_name[node_id]
get_comparison_value: (node_id, label) ->
if @sort_by_name
this_term = (label or node_id)
else
this_term = node_id
if @squash_case_during_sort is true # expose this as a setting
this_term = this_term.toLowerCase()
return this_term
add_alphabetically: (i_am_in, node_id, label) ->
label_lower = label.toLowerCase()
container = i_am_in[0][0]
this_term = @get_comparison_value(node_id, label)
for elem in container.children
elem_lower = (@id_to_name[elem.id] or elem.id).toLowerCase()
if (elem_lower > label_lower)
other_term = @get_comparison_value(elem.id, @id_to_name[elem.id])
if (other_term > this_term)
return @add_to_elem_before(i_am_in, node_id, "#"+elem.id, label)
# fall through and append if it comes before nothing
@add_to_elem_before(i_am_in, node_id, undefined, label)
add_to_elem_before: (i_am_in, node_id, before, label) ->
i_am_in.insert('div', before). # insert just appends if before is undef
attr('class','contents').
attr('id',node_id)
show_tree: (tree,i_am_in,listener,top) ->
show_tree: (tree, i_am_in, listener, top) ->
# http://stackoverflow.com/questions/14511872
top = not top? or top
for node_id,rest of tree
label = rest[0]
#label = "┗ " + rest[0]

# FIXME the creation of a node in the tree should be extracted into a method
# rather than being spread across this one and add_alphabetically.
# Setting @id_to_elem[node_id] should be in the new method
contents_of_me = @add_alphabetically(i_am_in, node_id, label)
@id_to_elem[node_id] = contents_of_me
msg = "show_tree() just did @id_to_elem[#{node_id}] = contents_of_me"
Expand Down

0 comments on commit 8d946b8

Please sign in to comment.