js/components/tree.js
// NPM IMPORTS
import assert from 'assert'
// COMMON IMPORTS
import T from '../../../node_modules/devapt-core-common/dist/js/utils/types'
// BROWSER IMPORTS
import Component from '../base/component'
const context = 'browser/components/tree'
/**
* @file UI Tree component class.
* @author Luc BORIES
* @license Apache-2.0
*/
export default class Tree extends Component
{
/**
* Creates an instance of Component.
*
* @param {object} arg_runtime - client runtime.
* @param {object} arg_state - component state.
* @param {string} arg_log_context - context of traces of this instance (optional).
*
* @returns {nothing}
*/
constructor(arg_runtime, arg_state, arg_log_context)
{
const log_context = arg_log_context ? arg_log_context : context
super(arg_runtime, arg_state, log_context)
this.is_tree_component = true
this.init()
}
/**
* Get container items count.
*
* @returns {nothing}
*/
ui_items_get_count()
{
}
/**
* Erase container items.
*
* @returns {nothing}
*/
ui_items_clear()
{
}
/**
* Append rows to the container.
*
* @param {array} arg_items_array - items array.
*
* @returns {nothing}
*/
ui_items_append(/*arg_items_array*/)
{
}
/**
* Prepend a row.
*
* @param {array} arg_items_array - rows array.
*
* @returns {nothing}
*/
ui_items_prepend(/*arg_items_array*/)
{
}
/**
* Remove a row at given position.
*
* @param {number} arg_index - row index.
*
* @returns {nothing}
*/
ui_items_remove_at_index(arg_index)
{
assert( T.isNumber(arg_index), context + ':ui_items_remove_at_index:bad index number' )
}
/**
* Remove a row at first position.
*
* @returns {nothing}
*/
ui_items_remove_first()
{
}
/**
* Remove a row at last position.
*
* @param {integer} arg_count - items count to remove.
*
* @returns {nothing}
*/
ui_items_remove_last(/*arg_count*/)
{
// console.log(context + ':ui_items_remove_last:arg_count', arg_count)
}
/**
* Init view.
*
* @returns {nothing}
*/
init()
{
}
/**
* Update tree.
*
* @param {object} arg_tree - tree nodes.
*
* @returns {nothing}
*/
update_tree(arg_tree)
{
if (arg_tree.datas)
{
arg_tree = arg_tree.datas
}
console.log('tree.update_tree', arg_tree)
const tree_id = this.get_dom_id()
this.max_depth = this.get_state_value('max_depth', 20)
this.max_depth = T.isNumber(this.max_depth) ? this.max_depth : 20
var collapsed = this.get_state_value('collapsed', false)
var html = ''
// html = '<table><tbody>'
html += this.render_node(arg_tree, 1, this.get_state_value('label') )
// html += '</tbody></table>'
// console.log('update_tree', html)
var tree_jqo = $('#' + tree_id)
tree_jqo.html(html)
if (collapsed)
{
$('div.node_content', tree_jqo).hide()
$('span.node_opened', tree_jqo).hide()
$('span.node_closed', tree_jqo).show()
} else {
$('div.node_content', tree_jqo).show()
$('span.node_opened', tree_jqo).show()
$('.node_closed', tree_jqo).hide()
}
$('a.node_a', tree_jqo).click(
function(ev)
{
var node = $(ev.currentTarget).parent()
$('div.node_content', node).toggle()
$('span.node_opened', node).toggle()
$('span.node_closed', node).toggle()
}
)
}
/**
*
*/
render_safe_string(arg_value)
{
// console.log('tree.render_safe_string', arg_value)
// arg_value = arg_value.replace('<script>', 'AscriptB').replace('A/scriptB', '\A/script\B')
// if (arg_value.indexOf('<') > -1)
// {
// // console.log('Tree:render_safe_string: value=%s', arg_value)
// return '<code>' + arg_value + '</code>'
// }
var translations = {
'<script>' :'!scripta!',
'</script>':'!scriptb!',
'<div>' :'!diva!',
'</div>':'!divb!',
'<li>' :'!lia!',
'</li>' :'!lib!',
'<ul>' :'!ula!',
'</ul>' :'!ulb!',
'<' :'!aaa!',
'>' :'!bbb!'
}
// arg_value = arg_value ? arg_value.toString().replace('<div>', '!diva!').replace('</div>', '!divb!') : arg_value
// return arg_value ? arg_value.toString().replace('<li>', '!lia!').replace('</li>', '!lib!').replace('<ul>', '!ula!').replace('</ul>', '!ulb!').replace('<', '!aaa!').replace('>', '!bbb!') : arg_value
if ( T.isString(arg_value) )
{
var tr = ''
Object.keys(translations).forEach(
function(key)
{
tr = translations[key]
arg_value = arg_value.replace(key, tr)
}
)
} else {
console.error('tree.render_safe_string: value is not a string', arg_value)
}
return arg_value
}
/**
*
*/
render_expandable_node(arg_label, arg_content, arg_content_is_safe)
{
arg_content_is_safe = T.isBoolean(arg_content_is_safe) ? arg_content_is_safe : false
// console.log('tree.render_expandable_node', arg_label, arg_content_is_safe)
var str = ''
str += '<div class="node">'
str += '<a class="node_a">'
str += '<span class="node_closed">\u25B9</span>'
str += '<span class="node_opened">\u25BF</span>'
str += '<b>' + arg_label + '</b>'
str += '</a>'
str += '<div class="node_content">'
str += arg_content_is_safe ? arg_content : this.render_safe_string(arg_content)
str += '</div>'
str += '</div>'
return str
}
/**
*
*/
render_node(arg_value, arg_depth, arg_label)
{
// console.log('tree.render_node', arg_label)
var self = this
var str = ''
arg_depth = arg_depth ? arg_depth : 1
arg_label = arg_label == 0 ? '0' : arg_label
arg_label = arg_label ? arg_label : 'no name'
if (arg_depth > this.max_depth)
{
console.log('MAX DEPTH ' + this.max_depth + ' is reached')
return '<p>MAX DEPTH ' + this.max_depth + ' is reached</p>'
}
if (T.isString(arg_value))
{
// console.log('tree.render_node with string content', arg_label)
arg_value = this.render_safe_string(arg_label) + '=' + this.render_safe_string(arg_value)
return '<span>' + arg_value + '</span>'
}
if (T.isNumber(arg_value))
{
// console.log('tree.render_node with number content', arg_label)
return '<span>' + this.render_safe_string(arg_label) + '=' + arg_value + '</span>'
}
if (T.isBoolean(arg_value))
{
// console.log('tree.render_node with boolean content', arg_label)
var value = arg_value ? 'true' : 'false'
return '<span>' + this.render_safe_string(arg_label) + '=' + value + '</span>'
}
if (T.isArray(arg_value))
{
// console.log('tree.render_node with array content', arg_label)
if (arg_value.length == 0)
{
return '<span>' + this.render_safe_string(arg_label) + '=' + '[]' + '</span>'
}
if (arg_value.length == 1)
{
return '<span>' + this.render_safe_string(arg_label) + '=' + '[' + '</span>' + this.render_node(arg_value[0], arg_depth + 1, '0') + ']'
}
try
{
arg_value.forEach(
function(value, index) {
str += self.render_node(value, arg_depth + 1, index)
}
)
}
catch(e)
{
// NOTHING TO DO
console.error(e)
}
return this.render_expandable_node(arg_label, str, true)
}
if (T.isObject(arg_value))
{
// console.log('tree.render_node with object content', arg_label)
try
{
Object.keys(arg_value).forEach(
function(key)
{
str += self.render_node(arg_value[key], arg_depth + 1, key)
}
)
}
catch(e)
{
// NOTHING TO DO
console.error(e)
}
return this.render_expandable_node(arg_label, str, true)
}
if ( T.isNull(arg_value))
{
// console.log('tree.render_node with null content', arg_label)
return ''
}
console.error(arg_value, 'value is unknow')
return '<p>unknow node of type [' + (typeof arg_value) + ']</p>'
}
/**
* On bindings refresh.
*
* @param {object} arg_operands - operands plain object.
*
* @returns {nothing}
*/
on_refresh(arg_operands)
{
// console.log('new state', arg_operands)
this.update_tree(arg_operands.datas)
}
}