forked from DGNum/gestioCOF
Merge branch 'Aufinal/clean_modelforest' into 'aureplop/kpsul_js_refactor'
Change ModelForest inner structure - Intermediary model for nodes removed - More descriptive ModelForest structure in constructor.structure, child_sort not defined in Python function anymore. - More intuitive access to parent and children of nodes (e.g. article.category, category.articles...) See merge request !215
This commit is contained in:
commit
7fc07ac603
3 changed files with 112 additions and 112 deletions
|
@ -450,22 +450,28 @@ class ArticleCategory extends ModelObject {
|
|||
|
||||
/**
|
||||
* Properties associated to a category
|
||||
* @default <tt>['id', 'name']</tt>
|
||||
* @default <tt>['id', 'name', 'has_addcost', 'article']</tt>
|
||||
* @see {@link Models.ModelObject.props|ModelObject.props}
|
||||
*/
|
||||
static get props() {
|
||||
return ['id', 'name', 'has_addcost'];
|
||||
return ['id', 'name', 'has_addcost', 'articles'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values for ArticleCategory model instances.
|
||||
* @default <tt>{ 'id': 0, 'name': '' }</tt>
|
||||
* @default <tt>{ 'id': 0, 'name': '', 'has_addcost': true, 'articles': [] }</tt>
|
||||
* @see {@link Models.ModelObject.default_data|ModelObject.default_data}
|
||||
*/
|
||||
static get default_data() {
|
||||
return {'id': 0, 'name': '', 'has_addcost': true};
|
||||
return {'id': 0, 'name': '', 'has_addcost': true, 'articles': []};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose name for ArticleCategory model
|
||||
* @default <tt>'category'</tt>
|
||||
*/
|
||||
static get verbose_name() { return 'category'; }
|
||||
|
||||
/**
|
||||
* @default {@link Formatters.ArticleCategoryFormatter}
|
||||
*/
|
||||
|
@ -490,7 +496,7 @@ class ArticleCategory extends ModelObject {
|
|||
class Article extends ModelObject {
|
||||
/**
|
||||
* Properties associated to an article
|
||||
* @default <tt>['id', 'name']</tt>
|
||||
* @default <tt>['id', 'name', 'price', 'stock', 'category']</tt>
|
||||
* @see {@link Models.ModelObject.props|ModelObject.props}
|
||||
*/
|
||||
static get props() {
|
||||
|
@ -510,6 +516,12 @@ class Article extends ModelObject {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verbose name for Article model
|
||||
* @default <tt>'article'</tt>
|
||||
*/
|
||||
static get verbose_name() { return 'article'; }
|
||||
|
||||
/**
|
||||
* @default {@link Formatters.ArticleFormatter}
|
||||
*/
|
||||
|
@ -535,22 +547,6 @@ class Article extends ModelObject {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Node for ModelForest object
|
||||
* @memberof Models
|
||||
*/
|
||||
class TreeNode {
|
||||
|
||||
constructor(type, content) {
|
||||
this.modelname = type;
|
||||
this.content = content;
|
||||
this.parent = null;
|
||||
this.children = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Simple {@link Models.ModelObject} forest.
|
||||
* @memberof Models
|
||||
|
@ -558,24 +554,11 @@ class TreeNode {
|
|||
class ModelForest {
|
||||
|
||||
/**
|
||||
* Dictionary associating types to classes
|
||||
* Abstract structure of the forest
|
||||
* @abstract
|
||||
* @type {Object}
|
||||
*/
|
||||
static get models() { return {}; }
|
||||
|
||||
/**
|
||||
* Comparison function for nodes
|
||||
* @abstract
|
||||
* @param {class} model Model to use for comparison
|
||||
* @param {Models.TreeNode} a
|
||||
* @param {Models.TreeNode} b
|
||||
* @see {@link Models.ModelObject.compare|ModelObject.compare}
|
||||
*/
|
||||
static compare(model, a, b) {
|
||||
return model.compare(a.content, b.content);
|
||||
}
|
||||
|
||||
static get structure() { return {}; }
|
||||
|
||||
/**
|
||||
* Creates empty instance and populates it with data if given
|
||||
|
@ -585,6 +568,19 @@ class ModelForest {
|
|||
this.from(datalist || []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shortcut functions to get parent and children of a given node
|
||||
*/
|
||||
get_parent(node) {
|
||||
var parent_name = this.constructor.structure[node.constructor.verbose_name].parent;
|
||||
return node[parent_name];
|
||||
}
|
||||
|
||||
get_children(node) {
|
||||
var child_name = this.constructor.structure[node.constructor.verbose_name].children;
|
||||
return node[child_name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches an object from the instance data, or creates it if
|
||||
* it does not exist yet.<br>
|
||||
|
@ -594,34 +590,38 @@ class ModelForest {
|
|||
* @param {number} direction
|
||||
*/
|
||||
get_or_create(data, direction) {
|
||||
var model = this.constructor.models[data.modelname];
|
||||
var struct_data = this.constructor.structure[data.modelname];
|
||||
var model = struct_data.model;
|
||||
|
||||
var existing = this.find_node(data.modelname, data.content.id);
|
||||
var existing = this.find(data.modelname, data.content.id);
|
||||
if (existing) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
var content = new this.constructor.models[data.modelname](data.content);
|
||||
var node = new TreeNode(data.modelname, content);
|
||||
|
||||
if (data.child_sort)
|
||||
node.child_sort = data.child_sort
|
||||
var node = new model(data.content);
|
||||
|
||||
if (direction <= 0) {
|
||||
if (data.parent) {
|
||||
var parent = this.get_or_create(data.parent, -1);
|
||||
node.parent = parent;
|
||||
parent.children.push(node);
|
||||
var parent_name = struct_data.parent;
|
||||
var parent_data = data.parent;
|
||||
var parent_struct = this.constructor.structure[parent_name];
|
||||
if (parent_data) {
|
||||
var parent_node = this.get_or_create(parent_data, -1);
|
||||
node[parent_name] = parent_node;
|
||||
parent_node[parent_struct.children].push(node);
|
||||
} else {
|
||||
this.roots.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (direction >= 0 && data.children) {
|
||||
for (let child_data of data.children) {
|
||||
var child = this.get_or_create(child_data, 1);
|
||||
child.parent = node;
|
||||
node.children.push(child);
|
||||
if (direction >= 0) {
|
||||
var child_name = struct_data.children;
|
||||
var child_struct = this.constructor.structure[child_name];
|
||||
if (data.children && data.children.length) {
|
||||
for (let child_data of data.children) {
|
||||
var child = this.get_or_create(child_data, 1);
|
||||
child[child_struct.parent] = node;
|
||||
node[child_name].push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -654,33 +654,43 @@ class ModelForest {
|
|||
* @param {Object} [options] Options for element render method
|
||||
*/
|
||||
render_element(node, templates, options) {
|
||||
var template = templates[node.modelname];
|
||||
var modelname = node.constructor.verbose_name;
|
||||
var struct_data = this.constructor.structure[modelname];
|
||||
|
||||
var template = templates[modelname];
|
||||
var options = options || {} ;
|
||||
|
||||
var $container = $('<div></div>');
|
||||
$container.attr('id', node.modelname+'-'+node.content.id);
|
||||
$container.attr('id', modelname+'-'+node.id);
|
||||
|
||||
var $rendered = node.content.display($(template), options);
|
||||
var $rendered = node.display($(template), options);
|
||||
$container.append($rendered);
|
||||
|
||||
//dirty
|
||||
node.children.sort(this.constructor.compare.bind(null, this.constructor.models[node.child_sort]));
|
||||
var children = this.get_children(node);
|
||||
|
||||
for (let child of node.children) {
|
||||
var $child = this.render_element(child, templates, options);
|
||||
$container.append($child);
|
||||
if (children && children.length) {
|
||||
if (struct_data.child_sort)
|
||||
children.sort(struct_data.child_sort);
|
||||
else
|
||||
children.sort(children[0].constructor.compare);
|
||||
|
||||
for (let child of children) {
|
||||
var $child = this.render_element(child, templates, options);
|
||||
$container.append($child);
|
||||
}
|
||||
}
|
||||
|
||||
return $container;
|
||||
}
|
||||
|
||||
add_to_container($container, node, templates, options) {
|
||||
var existing = node.parent ;
|
||||
var struct = this.constructor.structure;
|
||||
var existing = this.get_parent(node) ;
|
||||
var first_missing = node;
|
||||
|
||||
while (existing && !($container.find('#'+existing.modelname+'-'+existing.id))) {
|
||||
first_missing = existing ;
|
||||
existing = existing.parent;
|
||||
first_missing = existing;
|
||||
existing = this.get_parent(existing);
|
||||
}
|
||||
|
||||
var $to_insert = render_element(first_missing, templates, options);
|
||||
|
@ -696,7 +706,11 @@ class ModelForest {
|
|||
* @param {Object} [options] Options for element render method
|
||||
*/
|
||||
display($container, templates, options) {
|
||||
this.roots.sort(this.constructor.compare.bind(null, this.root_sort));
|
||||
if (this.constructor.root_sort)
|
||||
this.roots.sort(this.constructor.root_sort);
|
||||
else
|
||||
this.roots.sort(this.roots[0].constructor.compare);
|
||||
|
||||
for (let root of this.roots) {
|
||||
$container.append(this.render_element(root, templates, options));
|
||||
}
|
||||
|
@ -704,27 +718,6 @@ class ModelForest {
|
|||
return $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find if node already exists in given tree
|
||||
* @param {Models.TreeNode}
|
||||
*/
|
||||
find_node(modelname, id) {
|
||||
var result = null;
|
||||
|
||||
function recurse(node) {
|
||||
if (node.modelname === modelname && node.content.id === id)
|
||||
result = node;
|
||||
|
||||
for (let child of node.children)
|
||||
recurse(child);
|
||||
}
|
||||
|
||||
for (let root of this.roots)
|
||||
recurse(root);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs for each node (in a DFS order) the callback function
|
||||
* on node.content and node.parent.content, if node has given modelname.
|
||||
|
@ -732,19 +725,27 @@ class ModelForest {
|
|||
* @param {function} callback
|
||||
*/
|
||||
traverse(modelname, callback) {
|
||||
var that = this;
|
||||
function recurse(node) {
|
||||
if (node.modelname === modelname) {
|
||||
var parent = node.parent && node.parent.content || null;
|
||||
var children = node.children.map( (child) => child.content);
|
||||
callback(node.content, children, parent);
|
||||
if (node.constructor.verbose_name === modelname) {
|
||||
if (callback(node)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
for (let child of node.children)
|
||||
recurse(child);
|
||||
var children = that.get_children(node);
|
||||
if (children) {
|
||||
for (let child of children)
|
||||
if (recurse(child))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let root of this.roots)
|
||||
recurse(root);
|
||||
if (recurse(root))
|
||||
return ;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -755,9 +756,11 @@ class ModelForest {
|
|||
find(modelname, id) {
|
||||
var result = null;
|
||||
|
||||
function callback(content) {
|
||||
if (content.id == id)
|
||||
result = content ;
|
||||
function callback(node) {
|
||||
if (node.id == id) {
|
||||
result = node ;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
this.traverse(modelname, callback);
|
||||
|
@ -807,12 +810,19 @@ class ArticleList extends APIModelForest {
|
|||
/**
|
||||
* Default structure for ArticleList instances
|
||||
* @abstract
|
||||
* @default <tt>{'article': Article,
|
||||
'category': ArticleCategory}</tt>
|
||||
*/
|
||||
static get models() {
|
||||
return {'article': Article,
|
||||
'category': ArticleCategory};
|
||||
static get structure() {
|
||||
return {
|
||||
'article': {
|
||||
'model': Article,
|
||||
'parent': 'category',
|
||||
},
|
||||
'category': {
|
||||
'model': ArticleCategory,
|
||||
'children': 'articles',
|
||||
},
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -824,15 +834,6 @@ class ArticleList extends APIModelForest {
|
|||
static get url_model() {
|
||||
return Urls['kfet.kpsul.articles_data']();
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides model to sort root objects
|
||||
* {@see Models.ModelForest.constructor|ModelForest.constructor}
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this.root_sort = ArticleCategory;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -599,9 +599,9 @@ class ArticleAutocomplete {
|
|||
updateDisplay() {
|
||||
var that = this;
|
||||
|
||||
this.manager.list.traverse('category', function(category, articles) {
|
||||
this.manager.list.traverse('category', function(category) {
|
||||
var is_active = false;
|
||||
for (let article of articles) {
|
||||
for (let article of category.articles) {
|
||||
if (that.matching.indexOf(article) != -1) {
|
||||
is_active = true;
|
||||
that._$container.find('#article-'+article.id).show();
|
||||
|
|
|
@ -1481,7 +1481,6 @@ def kpsul_articles_data(request):
|
|||
'name': article.category.name,
|
||||
'has_addcost': article.category.has_addcost,
|
||||
},
|
||||
'child_sort': 'article',
|
||||
}
|
||||
})
|
||||
return JsonResponse(articlelist, safe=False)
|
||||
|
|
Loading…
Reference in a new issue