diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js
index d58bda1a..9beefbb6 100644
--- a/kfet/static/kfet/js/kfet.api.js
+++ b/kfet/static/kfet/js/kfet.api.js
@@ -251,7 +251,7 @@ class APIModelObject extends ModelObject {
$.getJSON(this.url_object, api_options)
.done(function (json, textStatus, jqXHR) {
- that.from(json)
+ that.from(json);
on_success(json, textStatus, jqXHR);
})
.fail(on_error);
@@ -498,7 +498,7 @@ class ArticleCategory extends ModelObject {
* @default 'article_category'
* @see {@link Models.ModelObject.verbose_name[ModelObject.verbose_name}
*/
- static get verbose_name() { return 'article_category'; }
+ static get verbose_name() { return 'category'; }
/**
* @default {@link Formatters.ArticleCategoryFormatter}
@@ -589,13 +589,6 @@ class ModelList {
});
}
- /**
- * 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=[]]
@@ -664,31 +657,32 @@ class ModelList {
}
/**
- * Renders an element (and all its offspring) and appends it to the given container.
- * Returns the completed container
- * @param {jQuery} $container
+ * Renders an element (and all its offspring) and returns the
+ * corresponding jQuery object.
* @param {Models.ModelObject} elt
+ * @param {Object} templates Templates to render each model
* @param {Object} [options] Options for element render method
*/
- render_element($container, elt, options) {
- var depth = this.names.indexOf(elt.constructor.verbose_name);
+ render_element(elt, templates, options) {
+ var name = elt.constructor.verbose_name;
+ var depth = this.names.indexOf(name);
+ var template = templates[name];
if (depth == -1) {
return $();
} else if (depth == 0) {
- $container.append(elt.display($(this.constructor.templates[0]), options));
- return $container;
+ return elt.display($(template), options);
} 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));
+ $container = elt.display($(template), options);
+ $container.attr('data'+name+'id', elt.id);
for (let child of children) {
- this.render_element($container, child, options);
+ $container.append(this.render_element(child, templates, options));
}
return $container;
@@ -698,21 +692,110 @@ class ModelList {
/**
* Display stored data in container.
* @param {jQuery} $container
+ * @param {Object} templates Templates to render each model
* @param {Object} [options] Options for element render method
*/
- display($container, options) {
+ display($container, templates, 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);
+ $container.append(this.render_element(root, templates, options);
}
return $container;
}
+
+ /**
+ * Find instance in data matching given properties.
+ * @param {class} model
+ * @param {Object} props Properties to match
+ */
+ find(model, props) {
+ if (!this.constructor.models.find(model)) {
+ return undefined ;
+ }
+
+ return this.data[model.verbose_name].find(function(v) {
+ for (let key in props) {
+ if (v[key] !== props[key])
+ return false;
+ }
+ return true;
+ });
+ }
}
+
+/**
+ * Describes a model list that can be filled through API.
+ * @extends Models.ModelList
+ * @memberof Models
+ */
+class APIModelList extends ModelList {
+
+ /**
+ * Request url to fill the model.
+ * @abstract
+ * @type {string}
+ */
+ static get url_model() {}
+
+ /**
+ * Fills the instance with distant data. It sends a GET HTTP request to
+ * {@link Models.APIModelList#url_model}.
+ * @param {object} [api_options] Additional data appended to the request.
+ * @param {jQueryAjaxSuccess} [on_success] A function to be called if the request succeeds.
+ * @param {jQueryAjaxError} [on_error] A function to be called if the request fails.
+ */
+ fromAPI(api_options, on_success, on_error) {
+ var that = this;
+
+ api_options = api_options || {}
+ on_success = on_success || $.noop;
+ on_error = on_error || $.noop;
+
+ api_options['format'] = 'json';
+
+ $.getJSON(this.url_model, api_options)
+ .done(function(json, textStatus, jqXHR) {
+ that.from(json);
+ on_success(json, textStatus, jqXHR);
+ })
+ .fail(on_error);
+ }
+}
+
+
+/**
+ * ArticleList model. Can be accessed through API.
+ * @extends Models.APIModelList
+ * @memberof Models
+ */
+class ArticleList extends APIModelList {
+
+ /**
+ * Default structure for ArticleList instances
+ * @abstract
+ * @default [Article, ArticleCategory]
+ */
+ static get models() {
+ return [Article, ArticleCategory];
+ }
+
+ /**
+ * Default url to get ArticlList data
+ * @abstract
+ * @default django-js-reverse('kfet.kpsul.articles_data')
+ * @see {@link Models.APIModelList.url_model|APIModelList.url_model}
+ */
+ static get url_model {
+ return Urls['kfet.kpsul.articles_data'];
+ }
+
+
+
/* ---------- ---------- */
/**