diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js
index e0bc2c35..a655786d 100644
--- a/kfet/static/kfet/js/kfet.api.js
+++ b/kfet/static/kfet/js/kfet.api.js
@@ -107,13 +107,6 @@ class ModelObject {
*/
static get default_data() { return {}; }
- /**
- * Verbose name so refer to this model
- * @abstract
- * @type {string}
- */
- static get verbose_name() { return ""; }
-
/**
* Create new instance from data or default values.
* @param {Object} [data={}] - data to store in instance
@@ -170,14 +163,24 @@ class ModelObject {
return formatter.render(this, $container, options);
}
+ /**
+ * Returns a string value for the model, to use in comparisons
+ * @see {@link Models.ModelObject.compare|ModelObject.compare}
+ */
+ comparevalue() {
+ return this.id.toString();
+ }
+
/**
* Compare function between two instances of the model
+ * by serializing them using comparevalue().
* @abstract
* @param {a} Models.ModelObject
* @param {b} Models.ModelObject
+ * @see {@link Models.ModelObject.comparevalue|ModelObject.comparevalue}
*/
static compare(a, b) {
- return a.id - b.id ;
+ return a.comparevalue().localeCompare(b.comparevalue());
}
}
@@ -493,13 +496,6 @@ class ArticleCategory extends ModelObject {
return {'id': 0, 'name': ''};
}
- /**
- * Verbose name for ArticleCategory model.
- * @default 'article_category'
- * @see {@link Models.ModelObject.verbose_name[ModelObject.verbose_name}
- */
- static get verbose_name() { return 'category'; }
-
/**
* @default {@link Formatters.ArticleCategoryFormatter}
*/
@@ -511,8 +507,8 @@ class ArticleCategory extends ModelObject {
* Comparison function between ArticleCategory model instances.
* @see {@link Models.ModelObject.compare|ModelObject.compare}
*/
- static compare(a, b) {
- return a.name.localeCompare(b.name);
+ comparevalue() {
+ return this.name ;
}
}
@@ -544,13 +540,6 @@ class Article extends ModelObject {
};
}
- /**
- * Verbose name for Article model
- * @default 'article'
- * @see {@link Models.ModelObject.verbose_name|ModelObject.verbose_name}
- */
- static get verbose_name() { return 'article'; }
-
/**
* @default {@link Formatters.ArticleFormatter}
*/
@@ -562,8 +551,8 @@ class Article extends ModelObject {
* Comparison function between Article model instances.
* @see {@link Models.ModelObject.compare|ModelObject.compare}
*/
- static compare(a, b) {
- return a.name.localeCompare(b.name);
+ comparevalue() {
+ return a.name;
}
// Take care of 'price' type
@@ -572,6 +561,11 @@ class Article extends ModelObject {
set price(v) { this._price = floatCheck(v); }
}
+
+/**
+ * Node for ModelForest object
+ * @memberof Models
+ */
class TreeNode {
constructor(type, content) {
@@ -584,15 +578,15 @@ class TreeNode {
/**
- * Simple {@link Models.ModelObject} list.
+ * Simple {@link Models.ModelObject} forest.
* @memberof Models
*/
-class ModelTree {
+class ModelForest {
/**
- * Nested structure of the list
+ * Dictionary associating types to classes
* @abstract
- * @type {Models.ModelObject[]}
+ * @type {Object}
*/
static get models() { return {}; }
@@ -602,7 +596,6 @@ class ModelTree {
* @param {Object[]} [datalist=[]]
*/
constructor(datalist) {
- this._root = new TreeNode({}) ;
this.from(datalist || []);
}
@@ -611,10 +604,10 @@ class ModelTree {
* it does not exist yet.
* If direction >= 0, parent objects are created recursively.
* If direction <= 0, child objects are created recursively.
- * @param {number} depth depth on the nested structure of the list
* @param {Object} data
+ * @param {number} direction
*/
- get_or_create(data, direction=0) {
+ get_or_create(data, direction) {
var model = this.constructor.models[data.type];
var existing = this.find(data.type, data.content.id);
@@ -622,13 +615,17 @@ class ModelTree {
return existing;
}
- var content = new this.constructor.models[data.type]();
+ var content = new this.constructor.models[data.type](data.content);
var node = new TreeNode(data.type, content);
if (direction <= 0) {
- var parent = data.parent ? this.get_or_create(data.parent, -1) : this._root;
- node.parent = parent;
- parent.children.push(node);
+ if (data.parent) {
+ var parent = this.get_or_create(data.parent, -1);
+ node.parent = parent;
+ parent.children.push(node);
+ } else {
+ this.roots.push(node);
+ }
}
if (direction >= 0) {
@@ -643,65 +640,64 @@ class ModelTree {
}
/**
- * Resets then populates the instance with the given data, starting from
- * the lowest level Models.ModelObject in {@link Models.ModelList#models|models}.
+ * Resets then populates the instance with the given data.
* @param {Object[]} datalist
*/
from(datalist) {
-
- for (let key of this.constructor.names) {
- this.data[key] = [];
- }
-
+ this.roots = [];
for (let data of datalist) {
this.get_or_create(data, 0);
}
}
/**
- * Removes all Models.ModelObject from the list.
+ * Removes all Models.TreeNode from the tree.
*/
clear() {
this.from([]);
}
/**
- * Renders an element (and all its offspring) and returns the
+ * Renders a node (and all its offspring) and returns the
* corresponding jQuery object.
- * @param {Models.ModelObject} elt
+ * @param {Models.TreeNode} node
* @param {Object} templates Templates to render each model
* @param {Object} [options] Options for element render method
*/
- render_element(elt, templates, options) {
- var name = elt.constructor.verbose_name;
- var depth = this.constructor.names.indexOf(name);
- var template = templates[name];
- var options = options || {} ;
+ render_element(node, templates, options) {
+ var template = templates[node.type];
+ var options = options || {} ;
- if (depth == -1) {
- return $();
- } else if (depth == 0) {
- var $rendered = elt.display($(template), options);
- $rendered.attr('data-'+name+'-id', elt.id);
- return $rendered;
- } else {
- var child_model = this.constructor.models[depth-1];
- var children = this.data[child_model.verbose_name]
- .filter(v => v[name].id == elt.id) ;
- children.sort(child_model.compare);
+ var $container = $('