diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js
index 0dbc03f2..d58bda1a 100644
--- a/kfet/static/kfet/js/kfet.api.js
+++ b/kfet/static/kfet/js/kfet.api.js
@@ -288,154 +288,6 @@ class APIModelObject extends ModelObject {
}
-/**
- * Simple {@link Models.ModelObject} list.
- * @memberof Models
- */
-class ModelList {
-
- /**
- * Nested structure of the list
- * @abstract
- * @type {Models.ModelObject[]}
- */
- static get models() { return []; }
-
- /**
- * Verbose names for list models
- * @abstract
- * @type {string[]}
- */
- static get names() {
- return this.models.map(function(v) {
- return v.constructor.verbose_name;
- });
- }
-
- /**
- * Templates used to render the different elements
- * @abstract
- * @type {string[]}
- */
- static get templates() { return []; }
-
- /**
- * Creates empty instance and populates it with data if given
- * @param {Object[]} [datalist=[]]
- */
- constructor(datalist) {
- this.from(datalist || []);
- }
-
- /**
- * Fetches an object from the instance data, or creates it if
- * it does not exist yet.
- * Parent objects are created recursively if needed.
- * @param {number} depth depth on the nested structure of the list
- * @param {Object} data
- */
- get_or_create(depth, data) {
- var model = this.constructor.models[depth];
- var name = model.constructor.verbose_name ;
-
- var existing = this.data[name].find(function (v){
- return v.id === data['id'] ;
- }) ;
-
- if (existing) {
- return existing;
- }
-
- if (depth == this.constructor.models.length) {
- var created = new model(data) ;
- return created ;
- } else {
- var par_name = this.constructor.models[depth+1]
- .constructor.verbose_name;
-
- var par_data = data[par_name];
- var created = new model(data);
- var parnt = this.get_or_create(depth+1, par_data);
- created[par_name] = parnt;
-
- this.data[name].push(created);
- return created ;
- }
- }
-
- /**
- * Resets then populates the instance with the given data, starting from
- * the lowest level Models.ModelObject in {@link Models.ModelList#models|models}.
- * @param {Object[]} datalist
- */
- from(datalist) {
-
- for (let key of this.constructor.names) {
- this.data[key] = [];
- }
-
- for (let data of datalist) {
- this.get_or_create(data, 0);
- }
- }
-
- /**
- * Removes all Models.ModelObject from the list.
- */
- clear() {
- this.from([]);
- }
-
- /**
- * Renders an element (and all its offspring) and appends it to the given container.
- * Returns the completed container
- * @param {jQuery} $container
- * @param {Models.ModelObject} elt
- * @param {Object} [options] Options for element render method
- */
- render_element($container, elt, options) {
- var depth = this.names.indexOf(elt.constructor.verbose_name);
-
- if (depth == -1) {
- return $();
- } else if (depth == 0) {
- $container.append(elt.display($(this.constructor.templates[0]), options));
- return $container;
- } else {
- var name = this.constructor.names[depth];
- 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);
-
- $container.append(elt.display($(this.constructor.templates[depth]), options));
-
- for (let child of children) {
- this.render_element($container, child, options);
- }
-
- return $container;
- }
- }
-
- /**
- * Display stored data in container.
- * @param {jQuery} $container
- * @param {Object} [options] Options for element render method
- */
- display($container, options) {
- var root_model = this.constructor.models[this.constructor.models.length-1];
- var roots = this.data[root_model.verbose_name];
- roots.sort(root_model.compare);
-
- for (let root of roots) {
- this.render_element($container, root, options);
- }
-
- return $container;
- }
-}
-
/**
* Account model. Can be accessed through API.
* @extends Models.APIModelObject
@@ -641,12 +493,27 @@ 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 'article_category'; }
+
/**
* @default {@link Formatters.ArticleCategoryFormatter}
*/
formatter() {
return ArticleCategoryFormatter;
}
+
+ /**
+ * Comparison function between ArticleCategory model instances.
+ * @see {@link Models.ModelObject.compare|ModelObject.compare}
+ */
+ static compare(a, b) {
+ return a.name.localeCompare(b.name);
+ }
}
/**
@@ -677,6 +544,13 @@ class Article extends ModelObject {
};
}
+ /**
+ * Verbose name for Article model
+ * @default 'article'
+ * @see {@link Models.ModelObject.compare|ModelObject.compare}
+ */
+ static get verbose_name() { return 'article'; }
+
/**
* @default {@link Formatters.ArticleCategoryFormatter}
*/
@@ -690,6 +564,155 @@ class Article extends ModelObject {
set price(v) { this._price = floatCheck(v); }
}
+
+/**
+ * Simple {@link Models.ModelObject} list.
+ * @memberof Models
+ */
+class ModelList {
+
+ /**
+ * Nested structure of the list
+ * @abstract
+ * @type {Models.ModelObject[]}
+ */
+ static get models() { return []; }
+
+ /**
+ * Verbose names for list models
+ * @abstract
+ * @type {string[]}
+ */
+ static get names() {
+ return this.models.map(function(v) {
+ return v.constructor.verbose_name;
+ });
+ }
+
+ /**
+ * Templates used to render the different elements
+ * @abstract
+ * @type {string[]}
+ */
+ static get templates() { return []; }
+
+ /**
+ * Creates empty instance and populates it with data if given
+ * @param {Object[]} [datalist=[]]
+ */
+ constructor(datalist) {
+ this.from(datalist || []);
+ }
+
+ /**
+ * Fetches an object from the instance data, or creates it if
+ * it does not exist yet.
+ * Parent objects are created recursively if needed.
+ * @param {number} depth depth on the nested structure of the list
+ * @param {Object} data
+ */
+ get_or_create(depth, data) {
+ var model = this.constructor.models[depth];
+ var name = model.constructor.verbose_name ;
+
+ var existing = this.data[name].find(function (v){
+ return v.id === data['id'] ;
+ }) ;
+
+ if (existing) {
+ return existing;
+ }
+
+ if (depth == this.constructor.models.length) {
+ var created = new model(data) ;
+ return created ;
+ } else {
+ var par_name = this.constructor.models[depth+1]
+ .constructor.verbose_name;
+
+ var par_data = data[par_name];
+ var created = new model(data);
+ var parnt = this.get_or_create(depth+1, par_data);
+ created[par_name] = parnt;
+
+ this.data[name].push(created);
+ return created ;
+ }
+ }
+
+ /**
+ * Resets then populates the instance with the given data, starting from
+ * the lowest level Models.ModelObject in {@link Models.ModelList#models|models}.
+ * @param {Object[]} datalist
+ */
+ from(datalist) {
+
+ for (let key of this.constructor.names) {
+ this.data[key] = [];
+ }
+
+ for (let data of datalist) {
+ this.get_or_create(data, 0);
+ }
+ }
+
+ /**
+ * Removes all Models.ModelObject from the list.
+ */
+ clear() {
+ this.from([]);
+ }
+
+ /**
+ * Renders an element (and all its offspring) and appends it to the given container.
+ * Returns the completed container
+ * @param {jQuery} $container
+ * @param {Models.ModelObject} elt
+ * @param {Object} [options] Options for element render method
+ */
+ render_element($container, elt, options) {
+ var depth = this.names.indexOf(elt.constructor.verbose_name);
+
+ if (depth == -1) {
+ return $();
+ } else if (depth == 0) {
+ $container.append(elt.display($(this.constructor.templates[0]), options));
+ return $container;
+ } else {
+ var name = this.constructor.names[depth];
+ 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);
+
+ $container.append(elt.display($(this.constructor.templates[depth]), options));
+
+ for (let child of children) {
+ this.render_element($container, child, options);
+ }
+
+ return $container;
+ }
+ }
+
+ /**
+ * Display stored data in container.
+ * @param {jQuery} $container
+ * @param {Object} [options] Options for element render method
+ */
+ display($container, options) {
+ var root_model = this.constructor.models[this.constructor.models.length-1];
+ var roots = this.data[root_model.verbose_name];
+ roots.sort(root_model.compare);
+
+ for (let root of roots) {
+ this.render_element($container, root, options);
+ }
+
+ return $container;
+ }
+}
+
/* ---------- ---------- */
/**