From 643503269e528281f0054450f86a48a8bb8b58f0 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 2 Mar 2017 06:50:47 -0300 Subject: [PATCH 01/38] add Article and Category models --- kfet/static/kfet/js/kfet.api.js | 103 +++++++++ kfet/templates/kfet/kpsul.html | 397 ++++++++++++++++++++++++++++++++ 2 files changed, 500 insertions(+) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 7836fcb9..21a67c9c 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -449,6 +449,79 @@ class Statement extends ModelObject { } +/** + * ArticleCategory model. Cannot be accessed through API. + * @extends Models.ModelObject + * @memberof Models + */ +class ArticleCategory extends ModelObject { + + /** + * Properties associated to a category + * @default ['id', 'name'] + * @see {@link Models.ModelObject.props|ModelObject.props} + */ + static get props() { + return ['id', 'name']; + } + + /** + * Default values for ArticleCategory model instances. + * @default { 'id': 0, 'name': '' } + * @see {@link Models.ModelObject.default_data|ModelObject.default_data} + */ + static get default_data() { + return {'id': 0, 'name': ''}; + } + + /** + * @default {@link Formatters.ArticleCategoryFormatter} + */ + formatter() { + return ArticleCategoryFormatter; + } +} + +/** + * Article model. Cannot be accessed through API. + * @extends Models.ModelObject + * @memberof Models + */ +class Article extends ModelObject { + /** + * Properties associated to an article + * @default ['id', 'name'] + * @see {@link Models.ModelObject.props|ModelObject.props} + */ + static get props() { + return ['id', 'name', 'price', 'stock', 'category']; + } + + /** + * Default values for Article model instances. + * @default { 'id': 0, 'name': '', 'price': 0, 'stock': 0, + * 'category': new ArticleCategory() } + * @see {@link Models.ModelObject.default_data|ModelObject.default_data} + */ + static get default_data() { + return { + 'id': 0, 'name': '', 'price': 0, 'stock': 0, + 'category': new ArticleCategory(), + }; + } + + /** + * @default {@link Formatters.ArticleCategoryFormatter} + */ + formatter() { + return ArticleFormatter; + } + + // Take care of 'price' type + // API currently returns a string object (serialization of Decimal type within Django) + get price() { return this._price; } + set price(v) { this._price = floatCheck(v); } +} /* ---------- ---------- */ @@ -683,3 +756,33 @@ class StatementFormatter extends Formatter { } } + + +/** + * @memberof Formatters + * @extends Formatters.Formatter + */ + +class ArticleCategoryFormatter extends Formatter { + + /** + * Properties renderable to html. + * @default {@link Models.Statement.props} + */ + static get props() { + return ArticleCategory.props; + } + + static get _data_stock() { + return { + 'default': '', 'low': 'low', + 'ok': 'ok', 'neg': 'neg', + }; + } + + static attr_data_stock(a) { + if (a.stock >= 5) { return this._data_stock.ok; } + else if (a.stock >= -5) { return this._data_stock.low; } + else /* a.stock < -5 */ { return this._data_stock.neg; } + } +} diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 7fc56605..6454afa9 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -189,6 +189,403 @@ function booleanCheck(v) { return v == true; } +function functionCheck(v) { + if (typeof v === 'function') + return v; + return function(){}; +} + +function restrict(obj, attr_list) { + var restricted = {} ; + for (let attr of attr_list) { + restricted[attr] = obj[attr] ; + } + return restricted ; +} + +class ArticleCategory { + + constructor(id, name) { + this.id = id; + this.name = name; + } + + get id() { return this._id; } + + set id(v) { this._id = intCheck(v); } + + html(template) { + var $template = $(template) + $template.attr('id', 'data-category-'+this.id); + $template.find('td').text(this.name); + return $template ; + } + + static compare(a, b) { + return a.name.localeCompare(b.name) ; + } +} + +class Article { + + constructor () { + $.extend(this, this.constructor.default_data); + } + + static get default_data() { + return { + 'id': 0, 'name': '', 'price': 0, 'stock': 0, + 'category': new ArticleCategory(), + }; + } + + get id() { return this._id; } + get price() { return this._price; } + get stock() { return this._stock; } + + set id(v) { this._id = intCheck(v); } + set price(v) { this._price = floatCheck(v); } + set stock(v) { this._stock = intCheck(v); } + + get str_price_ukf() { + return amountToUKF(this.price, false); + } + + static get _data_stock_ok() { return ''; } + static get _data_stock_low() { return 'low'; } + static get _data_stock_neg() { return 'neg'; } + + get data_stock() { + var stock = this.stock ; + if (stock >= 5) { return this.constructor._data_stock_ok; } + else if (stock >= -5) { return this.constructor._data_stock_low; } + else /* stock < -5 */ { return this.constructor._data_stock_neg; } + } + + from(data) { + $.extend(this, this.constructor.default_data, data); + } + + html(template) { + var $template = $(template); + $template + .find('.name').text(this.name).end() + .find('.price').text(this.str_price_ukf).end() + .find('.stock').text(this.stock).end(); + $template.attr('id', 'data-article-'+this.id); + $template.attr('data-stock', this.data_stock); + return $template ; + } + + static compare(a, b) { + return a.name.localeCompare(b.name) ; + } + + reset() { + this.from({}); + } +} + +class ArticleList { + constructor() { + this.articles = []; + this.categories = []; + } + + get_or_create(id, name) { + var category = this.categories.find(c => c.id === id); + if (!category) { + category = new ArticleCategory(id, name); + this.categories.push(category); + } + return category; + } + + from(data, callback) { + callback = functionCheck(callback); + + for (let article_data of data['articles']) { + var category = this.get_or_create(article_data['category_id'], article_data['category__name']) ; + article_data = restrict(article_data, ['name', 'price', 'stock', 'id']) ; + article_data['category'] = category ; + + var article = new Article() ; + article.from(article_data) ; + this.articles.push(article) ; + } + + callback() ; + } + + fromAPI(on_success, on_error) { + on_error = functionCheck(on_error); + var that = this ; + $.ajax({ + dataType: "json", + url : "{% url 'kfet.kpsul.articles_data' %}", + method : "GET", + }) + .done((data) => this.from(data, on_success)) + .fail(on_error); + } + + display($container, $article_template, $category_template) { + this.categories.sort(ArticleCategory.compare) ; + for (let cat of this.categories) { + var cat_articles = this.articles.filter(a => a.category.id === cat.id) ; + cat_articles.sort(Article.compare); + + $container.append(cat.html($category_template)) ; + for (let art of cat_articles) { + $container.append(art.html($article_template)) ; + } + } + } + + clear() { + this.articles = []; + this.categories = [] ; + } + + find_by_id(name) { + return this.articles.find(function(a) { + return a.name === name ; + }); + } + + get_from_elt($elt) { + var id = $elt.attr('id').split('-')[2]; + + return this.articles.find(function(article) { + return (article.id == id) ; + }); + } +} + +class ArticleManager { + + constructor(env) { + this._env = env; // Global K-Psul Manager + + this._$container = $('#articles_data tbody'); + this._$input = $('#article_autocomplete'); + this._$nb = $('#article_number'); + this._category_template = ''; + this._article_template = ''; + + this.selected = new Article() ; + this.list = new ArticleList() ; + this.autocomplete = new ArticleAutocomplete(this); + + this._init_events(); + } + + get nb() { + return this._$nb.val() ; + } + + display_list() { + this.list.display(this._$container, this._article_template, this._category_template) ; + } + + validate(article) { + this.selected.from(article) ; + this._$input.val(article.name); + this._$nb.val('1'); + this._$nb.focus().select(); + } + + unset() { + this.selected.reset(); + } + + is_empty() { + return this.selected.id == 0 ; + } + + reset_data() { + this._$container.find('tr').remove(); + this.list.clear(); + this.list.fromAPI(this.display_list.bind(this)) ; + } + + update_data(data) { + for (let article_dict of data) { + var article = this.list.articles.find(function(art) { + return (art.id == article_dict['id']); + }); + + // For now, article additions are disregarded + if (article) { + article.stock = article_dict['stock']; + this._$container.find('#data-article-'+article_dict['id']+' .stock') + .text(article_dict['stock']); + } + } + } + + reset() { + this.unset() ; + this._$nb.val(''); + this._$input.val(''); + this.autocomplete.showAll() ; + } + + _init_events() { + var that = this; + + // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 + var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; + var arrowKeys = /^(37|38|39|40)$/; + + //Global input event (to merge ?) + this._$input.on('keydown', function(e) { + if (e.keyCode == 13 && that._$input.val() == '') { + that._env.performOperations(); + } + }); + + this._$container.on('click', '.article', function() { + var article = that.list.get_from_elt($(this)) ; + that.validate(article); + }); + + this._$nb.on('keydown', function(e) { + if (e.keyCode == 13 && ArticleManager.check_nb(that.nb) && !that.is_empty()) { + that._env.addPurchase(that.selected, that.nb); + that.reset(); + that.focus(); + } + if (normalKeys.test(e.keyCode) || arrowKeys.test(e.KeyCode) || e.ctrlKey) { + if (e.ctrlKey && e.charCode == 65) + that._$nb.val(''); + return true ; + } + if (ArticleManager.check_nb(that.nb+e.key)) + return true; + return false; + + }); + } + + focus() { + this._$input.focus(); + return this; + } + + static check_nb(nb) { + return /^[0-9]+$/.test(nb) && nb > 0 && nb <= 24 ; + } +} + +class ArticleAutocomplete { + + constructor(article_manager) { + this.manager = article_manager; + this.matching = []; + this.active_categories = []; + this._$container = article_manager._$container ; + this._$input = $('#article_autocomplete'); + + this.showAll() ; + this._init_events(); + } + + _init_events() { + var that = this ; + + // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 + var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; + + this._$input + .on('keydown', function(e) { + var text = that._$input.val() ; + if (normalKeys.test(e.keyCode) || e.ctrlKey) { + // For the backspace key, we suppose the cursor is at the very end + if(e.keyCode == 8) { + that.update(text.substring(0, text.length-1), true); + } + return true ; + } + that.update(text+e.key, false); + + return false ; + + }); + + } + + update(prefix, backspace) { + + var article_list = this.manager.list ; + var lower = prefix.toLowerCase() ; + var that = this ; + this.matching = article_list.articles.filter(function(article) { + return article.name.toLowerCase() + .indexOf(lower) === 0 ; + }); + + this.active_categories = article_list.categories.filter(function(category) { + return that.matching.find(function(article) { + return article.category === category ; + }); + }); + + if (this.matching.length == 1) { + if (!backspace) { + this.manager.validate(this.matching[0]) ; + this.showAll() ; + } else { + this.manager.unset(); + this.updateDisplay(); + } + } else if (this.matching.length > 1) { + this.manager.unset(); + this.updateDisplay() ; + if (!backspace) + this.updatePrefix(); + } + } + + updateDisplay() { + var article_list = this.manager.list ; + for (let article of article_list.articles) { + if (this.matching.indexOf(article) > -1) { + this._$container.find('#data-article-'+article.id).show(); + } else { + this._$container.find('#data-article-'+article.id).hide(); + } + } + + for (let category of article_list.categories) { + if (this.active_categories.indexOf(category) > -1) { + this._$container.find('#data-category-'+category.id).show(); + } else { + this._$container.find('#data-category-'+category.id).hide(); + } + } + } + + updatePrefix() { + var lower = this.matching.map(function (article) { + return article.name.toLowerCase() ; + }); + + lower.sort() ; + var first = lower[0], last = lower[lower.length-1], + length = first.length, i = 0; + while (i < length && first.charAt(i) === last.charAt(i)) i++; + + this._$input.val(first.substring(0,i)) ; + } + + showAll() { + this.matching = this.manager.list.articles; + this.active_categories = this.manager.list.categories; + this.updateDisplay(); + } +} + $(document).ready(function() { 'use strict'; From db9c14f7683eeb48f2cb9cd54af2e58f734fc82c Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 6 Mar 2017 02:43:48 -0300 Subject: [PATCH 02/38] articlelist wip --- kfet/static/kfet/js/kfet.api.js | 96 ++++++++++++++++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 21a67c9c..3caf3662 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -71,7 +71,9 @@ class Config { * A model subclasses {@link Models.ModelObject}.
* A model whose instances can be got from API subclasses * {@link Models.APIModelObject}.
- * These two classes should not be used directly. + * A model to manage ModelObject lists + * {@link Models.ModelList}.
+ * These classes should not be used directly. *

* * Models with API support: @@ -105,6 +107,13 @@ 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 @@ -269,6 +278,91 @@ 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; + }); + } + + /** + * Fetches an object from the object 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([]); + } + +} + /** * Account model. Can be accessed through API. * @extends Models.APIModelObject From 2cc0e0cffee9e240fe2e49f009089fd691e6bd3b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 7 Mar 2017 17:57:40 -0300 Subject: [PATCH 03/38] modellist suite et fin --- kfet/static/kfet/js/kfet.api.js | 77 ++- kfet/static/kfet/js/log | 893 ++++++++++++++++++++++++++++++++ 2 files changed, 968 insertions(+), 2 deletions(-) create mode 100644 kfet/static/kfet/js/log diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 3caf3662..0dbc03f2 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -167,7 +167,17 @@ class ModelObject { */ display($container, options, formatter) { formatter = formatter || this.formatter(); - formatter.render(this, $container, options); + return formatter.render(this, $container, options); + } + + /** + * Compare function between two instances of the model + * @abstract + * @param {a} Models.ModelObject + * @param {b} Models.ModelObject + */ + static compare(a, b) { + return a.id - b.id ; } } @@ -302,8 +312,23 @@ 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=[]] + */ + constructor(datalist) { + this.from(datalist || []); + } + /** - * Fetches an object from the object data, or creates it if + * 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 @@ -361,6 +386,54 @@ class ModelList { 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; + } } /** diff --git a/kfet/static/kfet/js/log b/kfet/static/kfet/js/log new file mode 100644 index 00000000..83b0b71f --- /dev/null +++ b/kfet/static/kfet/js/log @@ -0,0 +1,893 @@ +kfet.api.js:13: ERROR - Parse error. identifier is a reserved word +class Config { +^ + +kfet.api.js:20: ERROR - Parse error. missing ; before statement + static _get_or_create_config() { + ^ + +kfet.api.js:23: ERROR - Parse error. invalid return + return window.config; + ^ + +kfet.api.js:24: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:31: ERROR - Parse error. missing ; before statement + static reset(callback) { + ^ + +kfet.api.js:32: ERROR - Parse error. syntax error + $.getJSON(Urls['kfet.kpsul.get_settings']()) + ^ + +kfet.api.js:39: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:45: ERROR - Parse error. missing ; before statement + static get(key) { + ^ + +kfet.api.js:47: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:54: ERROR - Parse error. missing ; before statement + static set(key, value) { + ^ + +kfet.api.js:59: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:94: ERROR - Parse error. identifier is a reserved word +class ModelObject { +^ + +kfet.api.js:101: ERROR - Parse error. missing ; before statement + static get props() { return []; } + ^ + +kfet.api.js:101: ERROR - Parse error. syntax error + static get props() { return []; } + ^ + +kfet.api.js:108: ERROR - Parse error. missing ; before statement + static get default_data() { return {}; } + ^ + +kfet.api.js:108: ERROR - Parse error. syntax error + static get default_data() { return {}; } + ^ + +kfet.api.js:115: ERROR - Parse error. missing ; before statement + static get verbose_name() { return ""; } + ^ + +kfet.api.js:115: ERROR - Parse error. syntax error + static get verbose_name() { return ""; } + ^ + +kfet.api.js:121: ERROR - Parse error. missing ; before statement + constructor(data) { + ^ + +kfet.api.js:122: ERROR - Parse error. syntax error + this.from(data || {}); + ^ + +kfet.api.js:123: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:129: ERROR - Parse error. syntax error + is_empty() { + ^ + +kfet.api.js:131: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:138: ERROR - Parse error. syntax error + formatter() { return Formatter; } + ^ + +kfet.api.js:138: ERROR - Parse error. syntax error + formatter() { return Formatter; } + ^ + +kfet.api.js:147: ERROR - Parse error. missing ; before statement + from(data) { + ^ + +kfet.api.js:149: ERROR - Parse error. syntax error + $.extend(this, this.constructor.default_data, data); + ^ + +kfet.api.js:150: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:155: ERROR - Parse error. syntax error + clear() { + ^ + +kfet.api.js:156: ERROR - Parse error. syntax error + this.from({}); + ^ + +kfet.api.js:157: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:168: ERROR - Parse error. missing ; before statement + display($container, options, formatter) { + ^ + +kfet.api.js:169: ERROR - Parse error. syntax error + formatter = formatter || this.formatter(); + ^ + +kfet.api.js:171: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:181: ERROR - Parse error. identifier is a reserved word +class APIModelObject extends ModelObject { +^ + +kfet.api.js:188: ERROR - Parse error. missing ; before statement + static get url_model() {} + ^ + +kfet.api.js:196: ERROR - Parse error. missing ; before statement + static url_object_for(api_pk) {} + ^ + +kfet.api.js:202: ERROR - Parse error. missing ; before statement + constructor(data) { + ^ + +kfet.api.js:207: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:213: ERROR - Parse error. missing ; before statement + get api_pk() { return this.id; } + ^ + +kfet.api.js:213: ERROR - Parse error. syntax error + get api_pk() { return this.id; } + ^ + +kfet.api.js:218: ERROR - Parse error. missing ; before statement + get url_object() { + ^ + +kfet.api.js:220: ERROR - Parse error. invalid return + return this.is_empty() ? '' : this.constructor.url_object_for(this.api_pk); + ^ + +kfet.api.js:221: ERROR - Parse error. invalid return + return this._url_object; + ^ + +kfet.api.js:222: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:224: ERROR - Parse error. missing ; before statement + set url_object(v) { this._url_object = v; } + ^ + +kfet.api.js:224: ERROR - Parse error. syntax error + set url_object(v) { this._url_object = v; } + ^ + +kfet.api.js:233: ERROR - Parse error. missing ; before statement + fromAPI(api_options, on_success, on_error) { + ^ + +kfet.api.js:248: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:258: ERROR - Parse error. missing ; before statement + get_by_apipk(api_pk, api_options, on_success, on_error) { + ^ + +kfet.api.js:259: ERROR - Parse error. syntax error + this.url_object = this.constructor.url_object_for(api_pk); + ^ + +kfet.api.js:261: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:270: ERROR - Parse error. missing ; before statement + display($container, options, formatter) { + ^ + +kfet.api.js:271: ERROR - Parse error. missing ; before statement + if (this.is_empty()) { + ^ + +kfet.api.js:272: ERROR - Parse error. syntax error + options.empty_props = true; + ^ + +kfet.api.js:274: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:276: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:285: ERROR - Parse error. identifier is a reserved word +class ModelList { +^ + +kfet.api.js:292: ERROR - Parse error. missing ; before statement + static get models() { return []; } + ^ + +kfet.api.js:292: ERROR - Parse error. syntax error + static get models() { return []; } + ^ + +kfet.api.js:299: ERROR - Parse error. missing ; before statement + static get names() { + ^ + +kfet.api.js:303: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:305: ERROR - Parse error. missing ; before statement + constructor(data) { + ^ + +kfet.api.js:306: ERROR - Parse error. syntax error + this.from(data || []); + ^ + +kfet.api.js:307: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:316: ERROR - Parse error. missing ; before statement + get_or_create(depth, data) { + ^ + +kfet.api.js:325: ERROR - Parse error. invalid return + return existing; + ^ + +kfet.api.js:330: ERROR - Parse error. invalid return + return created ; + ^ + +kfet.api.js:341: ERROR - Parse error. invalid return + return created ; + ^ + +kfet.api.js:343: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:350: ERROR - Parse error. missing ; before statement + from(datalist) { + ^ + +kfet.api.js:352: ERROR - Parse error. missing ) in parenthetical + for (let key of this.constructor.names) { + ^ + +kfet.api.js:353: ERROR - Parse error. syntax error + this.data[key] = []; + ^ + +kfet.api.js:354: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:356: ERROR - Parse error. missing ) in parenthetical + for (let data of datalist) { + ^ + +kfet.api.js:357: ERROR - Parse error. syntax error + this.get_or_create(data, 0); + ^ + +kfet.api.js:358: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:364: ERROR - Parse error. missing ; before statement + clear() { + ^ + +kfet.api.js:365: ERROR - Parse error. syntax error + this.from([]); + ^ + +kfet.api.js:366: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:375: ERROR - Parse error. identifier is a reserved word +class Account extends APIModelObject { +^ + +kfet.api.js:383: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:386: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:395: ERROR - Parse error. missing ; before statement + static get default_data() { + ^ + +kfet.api.js:397: ERROR - Parse error. missing ; before statement + 'id': 0, 'trigramme': '', 'name': '', 'nickname': '', 'email': '', + ^ + +kfet.api.js:398: ERROR - Parse error. syntax error + 'is_cof' : false, 'promo': '', 'balance': 0, 'is_frozen': false, + ^ + +kfet.api.js:399: ERROR - Parse error. syntax error + 'departement': '', + ^ + +kfet.api.js:407: ERROR - Parse error. identifier is a reserved word + static get url_model() { return Urls['kfet.account'](); } + ^ + +kfet.api.js:407: ERROR - Parse error. syntax error + static get url_model() { return Urls['kfet.account'](); } + ^ + +kfet.api.js:414: ERROR - Parse error. missing ; before statement + static url_object_for(trigramme) { + ^ + +kfet.api.js:416: ERROR - Parse error. invalid return + return Urls['kfet.account.read'](trigramme_url); + ^ + +kfet.api.js:417: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:422: ERROR - Parse error. missing ; before statement + get api_pk() { return this.trigramme; } + ^ + +kfet.api.js:422: ERROR - Parse error. syntax error + get api_pk() { return this.trigramme; } + ^ + +kfet.api.js:427: ERROR - Parse error. syntax error + formatter() { + ^ + +kfet.api.js:429: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:433: ERROR - Parse error. missing ; before statement + get balance() { return this._balance; } + ^ + +kfet.api.js:433: ERROR - Parse error. syntax error + get balance() { return this._balance; } + ^ + +kfet.api.js:434: ERROR - Parse error. missing ; before statement + set balance(v) { return this._balance = floatCheck(v); } + ^ + +kfet.api.js:434: ERROR - Parse error. syntax error + set balance(v) { return this._balance = floatCheck(v); } + ^ + +kfet.api.js:439: ERROR - Parse error. missing ; before statement + get balance_ukf() { return amountToUKF(this.balance, this.is_cof); } + ^ + +kfet.api.js:439: ERROR - Parse error. syntax error + get balance_ukf() { return amountToUKF(this.balance, this.is_cof); } + ^ + +kfet.api.js:449: ERROR - Parse error. identifier is a reserved word +class Checkout extends APIModelObject { +^ + +kfet.api.js:456: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:458: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:466: ERROR - Parse error. missing ; before statement + static get default_data() { + ^ + +kfet.api.js:468: ERROR - Parse error. missing ; before statement + 'id': 0, 'name': '', 'balance': 0, 'valid_from': '', 'valid_to': '', + ^ + +kfet.api.js:476: ERROR - Parse error. identifier is a reserved word + static get url_model() { return ''; } + ^ + +kfet.api.js:476: ERROR - Parse error. syntax error + static get url_model() { return ''; } + ^ + +kfet.api.js:483: ERROR - Parse error. missing ; before statement + static url_object_for(api_pk) { + ^ + +kfet.api.js:485: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:490: ERROR - Parse error. syntax error + formatter() { + ^ + +kfet.api.js:492: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:496: ERROR - Parse error. missing ; before statement + get balance() { return this._balance; } + ^ + +kfet.api.js:496: ERROR - Parse error. syntax error + get balance() { return this._balance; } + ^ + +kfet.api.js:497: ERROR - Parse error. missing ; before statement + set balance(v) { this._balance = floatCheck(v); } + ^ + +kfet.api.js:497: ERROR - Parse error. syntax error + set balance(v) { this._balance = floatCheck(v); } + ^ + +kfet.api.js:507: ERROR - Parse error. identifier is a reserved word +class Statement extends ModelObject { +^ + +kfet.api.js:514: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:516: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:524: ERROR - Parse error. missing ; before statement + static get default_data() { + ^ + +kfet.api.js:526: ERROR - Parse error. missing ; before statement + 'id': 0, 'at': '', 'balance_old': 0, 'balance_new': 0, 'by': '', + ^ + +kfet.api.js:533: ERROR - Parse error. missing ; before statement + formatter() { + ^ + +kfet.api.js:535: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:539: ERROR - Parse error. missing ; before statement + get balance_old() { return this._balance_old; } + ^ + +kfet.api.js:539: ERROR - Parse error. syntax error + get balance_old() { return this._balance_old; } + ^ + +kfet.api.js:540: ERROR - Parse error. missing ; before statement + set balance_old(v) { this._balance_old = floatCheck(v); } + ^ + +kfet.api.js:540: ERROR - Parse error. syntax error + set balance_old(v) { this._balance_old = floatCheck(v); } + ^ + +kfet.api.js:542: ERROR - Parse error. missing ; before statement + get balance_new() { return this._balance_new; } + ^ + +kfet.api.js:542: ERROR - Parse error. syntax error + get balance_new() { return this._balance_new; } + ^ + +kfet.api.js:543: ERROR - Parse error. missing ; before statement + set balance_new(v) { this._balance_new = floatCheck(v); } + ^ + +kfet.api.js:543: ERROR - Parse error. syntax error + set balance_new(v) { this._balance_new = floatCheck(v); } + ^ + +kfet.api.js:545: ERROR - Parse error. missing ; before statement + get at() { return this._at; } + ^ + +kfet.api.js:545: ERROR - Parse error. syntax error + get at() { return this._at; } + ^ + +kfet.api.js:546: ERROR - Parse error. missing ; before statement + set at(v) { this._at = moment.isMoment(v) ? v : moment.tz(v, 'UTC'); } + ^ + +kfet.api.js:546: ERROR - Parse error. syntax error + set at(v) { this._at = moment.isMoment(v) ? v : moment.tz(v, 'UTC'); } + ^ + +kfet.api.js:555: ERROR - Parse error. identifier is a reserved word +class ArticleCategory extends ModelObject { +^ + +kfet.api.js:562: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:564: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:571: ERROR - Parse error. missing ; before statement + static get default_data() { + ^ + +kfet.api.js:572: ERROR - Parse error. missing ; before statement + return {'id': 0, 'name': ''}; + ^ + +kfet.api.js:578: ERROR - Parse error. missing ; before statement + formatter() { + ^ + +kfet.api.js:580: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:588: ERROR - Parse error. identifier is a reserved word +class Article extends ModelObject { +^ + +kfet.api.js:594: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:596: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:604: ERROR - Parse error. missing ; before statement + static get default_data() { + ^ + +kfet.api.js:606: ERROR - Parse error. missing ; before statement + 'id': 0, 'name': '', 'price': 0, 'stock': 0, + ^ + +kfet.api.js:607: ERROR - Parse error. syntax error + 'category': new ArticleCategory(), + ^ + +kfet.api.js:614: ERROR - Parse error. missing ; before statement + formatter() { + ^ + +kfet.api.js:616: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:620: ERROR - Parse error. missing ; before statement + get price() { return this._price; } + ^ + +kfet.api.js:620: ERROR - Parse error. syntax error + get price() { return this._price; } + ^ + +kfet.api.js:621: ERROR - Parse error. missing ; before statement + set price(v) { this._price = floatCheck(v); } + ^ + +kfet.api.js:621: ERROR - Parse error. syntax error + set price(v) { this._price = floatCheck(v); } + ^ + +kfet.api.js:640: ERROR - Parse error. identifier is a reserved word +class Formatter { +^ + +kfet.api.js:642: ERROR - Parse error. missing ; before statement + static get props() { return []; } + ^ + +kfet.api.js:642: ERROR - Parse error. syntax error + static get props() { return []; } + ^ + +kfet.api.js:643: ERROR - Parse error. missing ; before statement + static get attrs() { return []; } + ^ + +kfet.api.js:643: ERROR - Parse error. syntax error + static get attrs() { return []; } + ^ + +kfet.api.js:653: ERROR - Parse error. missing ; before statement + static get(object, name, prefix) { + ^ + +kfet.api.js:654: ERROR - Parse error. syntax error + prefix = prefix || ''; + ^ + +kfet.api.js:657: ERROR - Parse error. invalid return + return this[method](object); + ^ + +kfet.api.js:658: ERROR - Parse error. invalid return + return object[name]; + ^ + +kfet.api.js:659: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:665: ERROR - Parse error. missing ; before statement + static get_prop(object, name) { + ^ + +kfet.api.js:667: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:673: ERROR - Parse error. missing ; before statement + static get_attr(obj, attr) { + ^ + +kfet.api.js:675: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:689: ERROR - Parse error. missing ; before statement + static render(object, $container, options) { + ^ + +kfet.api.js:690: ERROR - Parse error. syntax error + options.props = options.props || []; + ^ + +kfet.api.js:711: ERROR - Parse error. invalid return + return $container; + ^ + +kfet.api.js:712: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:721: ERROR - Parse error. identifier is a reserved word +class AccountFormatter extends Formatter { +^ + +kfet.api.js:727: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:729: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:735: ERROR - Parse error. missing ; before statement + static get attrs() { + ^ + +kfet.api.js:737: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:739: ERROR - Parse error. missing ; before statement + static get _data_balance() { + ^ + +kfet.api.js:741: ERROR - Parse error. missing ; before statement + 'default': '', 'frozen': 'frozen', + ^ + +kfet.api.js:742: ERROR - Parse error. syntax error + 'ok': 'ok', 'low': 'low', 'neg': 'neg', + ^ + +kfet.api.js:749: ERROR - Parse error. identifier is a reserved word + static prop_balance(a) { + ^ + +kfet.api.js:751: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:756: ERROR - Parse error. missing ; before statement + static prop_is_cof(a) { + ^ + +kfet.api.js:758: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:764: ERROR - Parse error. missing ; before statement + static attr_data_balance(a) { + ^ + +kfet.api.js:765: ERROR - Parse error. missing ; before statement + if (a.is_frozen) { return this._data_balance.frozen; } + ^ + +kfet.api.js:765: ERROR - Parse error. syntax error + if (a.is_frozen) { return this._data_balance.frozen; } + ^ + +kfet.api.js:766: ERROR - Parse error. invalid return + else if (a.balance >= 5) { return this._data_balance.ok; } + ^ + +kfet.api.js:767: ERROR - Parse error. invalid return + else if (a.balance >= 0) { return this._data_balance.low; } + ^ + +kfet.api.js:768: ERROR - Parse error. invalid return + else /* a.balance < 0 */ { return this._data_balance.neg; } + ^ + +kfet.api.js:769: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:778: ERROR - Parse error. identifier is a reserved word +class LIQFormatter extends AccountFormatter { +^ + +kfet.api.js:784: ERROR - Parse error. missing ; before statement + static get_prop() { + ^ + +kfet.api.js:786: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:791: ERROR - Parse error. missing ; before statement + static attr_data_balance(a) { return this._data_balance.ok; } + ^ + +kfet.api.js:791: ERROR - Parse error. syntax error + static attr_data_balance(a) { return this._data_balance.ok; } + ^ + +kfet.api.js:800: ERROR - Parse error. identifier is a reserved word +class CheckoutFormatter extends Formatter { +^ + +kfet.api.js:806: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:808: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:813: ERROR - Parse error. missing ; before statement + static prop_balance(c) { + ^ + +kfet.api.js:815: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:825: ERROR - Parse error. identifier is a reserved word +class StatementFormatter extends Formatter { +^ + +kfet.api.js:831: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:833: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:838: ERROR - Parse error. missing ; before statement + static prop_balance_old(s) { + ^ + +kfet.api.js:840: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:845: ERROR - Parse error. missing ; before statement + static prop_balance_new(s) { + ^ + +kfet.api.js:847: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:852: ERROR - Parse error. missing ; before statement + static prop_at(s) { + ^ + +kfet.api.js:854: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:864: ERROR - Parse error. identifier is a reserved word +class ArticleCategoryFormatter extends Formatter { +^ + +kfet.api.js:870: ERROR - Parse error. missing ; before statement + static get props() { + ^ + +kfet.api.js:872: ERROR - Parse error. syntax error + } + ^ + +kfet.api.js:874: ERROR - Parse error. missing ; before statement + static get _data_stock() { + ^ + +kfet.api.js:876: ERROR - Parse error. missing ; before statement + 'default': '', 'low': 'low', + ^ + +kfet.api.js:877: ERROR - Parse error. syntax error + 'ok': 'ok', 'neg': 'neg', + ^ + +kfet.api.js:881: ERROR - Parse error. identifier is a reserved word + static attr_data_stock(a) { + ^ + +kfet.api.js:882: ERROR - Parse error. missing ; before statement + if (a.stock >= 5) { return this._data_stock.ok; } + ^ + +kfet.api.js:882: ERROR - Parse error. syntax error + if (a.stock >= 5) { return this._data_stock.ok; } + ^ + +kfet.api.js:883: ERROR - Parse error. invalid return + else if (a.stock >= -5) { return this._data_stock.low; } + ^ + +kfet.api.js:884: ERROR - Parse error. invalid return + else /* a.stock < -5 */ { return this._data_stock.neg; } + ^ + +kfet.api.js:885: ERROR - Parse error. syntax error + } + ^ + +223 error(s), 0 warning(s) From c9cce5b12547dc5fdbca13c2ab3f8052a0f0d815 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 7 Mar 2017 17:58:10 -0300 Subject: [PATCH 04/38] remove temp file --- kfet/static/kfet/js/log | 893 ---------------------------------------- 1 file changed, 893 deletions(-) delete mode 100644 kfet/static/kfet/js/log diff --git a/kfet/static/kfet/js/log b/kfet/static/kfet/js/log deleted file mode 100644 index 83b0b71f..00000000 --- a/kfet/static/kfet/js/log +++ /dev/null @@ -1,893 +0,0 @@ -kfet.api.js:13: ERROR - Parse error. identifier is a reserved word -class Config { -^ - -kfet.api.js:20: ERROR - Parse error. missing ; before statement - static _get_or_create_config() { - ^ - -kfet.api.js:23: ERROR - Parse error. invalid return - return window.config; - ^ - -kfet.api.js:24: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:31: ERROR - Parse error. missing ; before statement - static reset(callback) { - ^ - -kfet.api.js:32: ERROR - Parse error. syntax error - $.getJSON(Urls['kfet.kpsul.get_settings']()) - ^ - -kfet.api.js:39: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:45: ERROR - Parse error. missing ; before statement - static get(key) { - ^ - -kfet.api.js:47: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:54: ERROR - Parse error. missing ; before statement - static set(key, value) { - ^ - -kfet.api.js:59: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:94: ERROR - Parse error. identifier is a reserved word -class ModelObject { -^ - -kfet.api.js:101: ERROR - Parse error. missing ; before statement - static get props() { return []; } - ^ - -kfet.api.js:101: ERROR - Parse error. syntax error - static get props() { return []; } - ^ - -kfet.api.js:108: ERROR - Parse error. missing ; before statement - static get default_data() { return {}; } - ^ - -kfet.api.js:108: ERROR - Parse error. syntax error - static get default_data() { return {}; } - ^ - -kfet.api.js:115: ERROR - Parse error. missing ; before statement - static get verbose_name() { return ""; } - ^ - -kfet.api.js:115: ERROR - Parse error. syntax error - static get verbose_name() { return ""; } - ^ - -kfet.api.js:121: ERROR - Parse error. missing ; before statement - constructor(data) { - ^ - -kfet.api.js:122: ERROR - Parse error. syntax error - this.from(data || {}); - ^ - -kfet.api.js:123: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:129: ERROR - Parse error. syntax error - is_empty() { - ^ - -kfet.api.js:131: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:138: ERROR - Parse error. syntax error - formatter() { return Formatter; } - ^ - -kfet.api.js:138: ERROR - Parse error. syntax error - formatter() { return Formatter; } - ^ - -kfet.api.js:147: ERROR - Parse error. missing ; before statement - from(data) { - ^ - -kfet.api.js:149: ERROR - Parse error. syntax error - $.extend(this, this.constructor.default_data, data); - ^ - -kfet.api.js:150: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:155: ERROR - Parse error. syntax error - clear() { - ^ - -kfet.api.js:156: ERROR - Parse error. syntax error - this.from({}); - ^ - -kfet.api.js:157: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:168: ERROR - Parse error. missing ; before statement - display($container, options, formatter) { - ^ - -kfet.api.js:169: ERROR - Parse error. syntax error - formatter = formatter || this.formatter(); - ^ - -kfet.api.js:171: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:181: ERROR - Parse error. identifier is a reserved word -class APIModelObject extends ModelObject { -^ - -kfet.api.js:188: ERROR - Parse error. missing ; before statement - static get url_model() {} - ^ - -kfet.api.js:196: ERROR - Parse error. missing ; before statement - static url_object_for(api_pk) {} - ^ - -kfet.api.js:202: ERROR - Parse error. missing ; before statement - constructor(data) { - ^ - -kfet.api.js:207: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:213: ERROR - Parse error. missing ; before statement - get api_pk() { return this.id; } - ^ - -kfet.api.js:213: ERROR - Parse error. syntax error - get api_pk() { return this.id; } - ^ - -kfet.api.js:218: ERROR - Parse error. missing ; before statement - get url_object() { - ^ - -kfet.api.js:220: ERROR - Parse error. invalid return - return this.is_empty() ? '' : this.constructor.url_object_for(this.api_pk); - ^ - -kfet.api.js:221: ERROR - Parse error. invalid return - return this._url_object; - ^ - -kfet.api.js:222: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:224: ERROR - Parse error. missing ; before statement - set url_object(v) { this._url_object = v; } - ^ - -kfet.api.js:224: ERROR - Parse error. syntax error - set url_object(v) { this._url_object = v; } - ^ - -kfet.api.js:233: ERROR - Parse error. missing ; before statement - fromAPI(api_options, on_success, on_error) { - ^ - -kfet.api.js:248: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:258: ERROR - Parse error. missing ; before statement - get_by_apipk(api_pk, api_options, on_success, on_error) { - ^ - -kfet.api.js:259: ERROR - Parse error. syntax error - this.url_object = this.constructor.url_object_for(api_pk); - ^ - -kfet.api.js:261: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:270: ERROR - Parse error. missing ; before statement - display($container, options, formatter) { - ^ - -kfet.api.js:271: ERROR - Parse error. missing ; before statement - if (this.is_empty()) { - ^ - -kfet.api.js:272: ERROR - Parse error. syntax error - options.empty_props = true; - ^ - -kfet.api.js:274: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:276: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:285: ERROR - Parse error. identifier is a reserved word -class ModelList { -^ - -kfet.api.js:292: ERROR - Parse error. missing ; before statement - static get models() { return []; } - ^ - -kfet.api.js:292: ERROR - Parse error. syntax error - static get models() { return []; } - ^ - -kfet.api.js:299: ERROR - Parse error. missing ; before statement - static get names() { - ^ - -kfet.api.js:303: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:305: ERROR - Parse error. missing ; before statement - constructor(data) { - ^ - -kfet.api.js:306: ERROR - Parse error. syntax error - this.from(data || []); - ^ - -kfet.api.js:307: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:316: ERROR - Parse error. missing ; before statement - get_or_create(depth, data) { - ^ - -kfet.api.js:325: ERROR - Parse error. invalid return - return existing; - ^ - -kfet.api.js:330: ERROR - Parse error. invalid return - return created ; - ^ - -kfet.api.js:341: ERROR - Parse error. invalid return - return created ; - ^ - -kfet.api.js:343: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:350: ERROR - Parse error. missing ; before statement - from(datalist) { - ^ - -kfet.api.js:352: ERROR - Parse error. missing ) in parenthetical - for (let key of this.constructor.names) { - ^ - -kfet.api.js:353: ERROR - Parse error. syntax error - this.data[key] = []; - ^ - -kfet.api.js:354: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:356: ERROR - Parse error. missing ) in parenthetical - for (let data of datalist) { - ^ - -kfet.api.js:357: ERROR - Parse error. syntax error - this.get_or_create(data, 0); - ^ - -kfet.api.js:358: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:364: ERROR - Parse error. missing ; before statement - clear() { - ^ - -kfet.api.js:365: ERROR - Parse error. syntax error - this.from([]); - ^ - -kfet.api.js:366: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:375: ERROR - Parse error. identifier is a reserved word -class Account extends APIModelObject { -^ - -kfet.api.js:383: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:386: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:395: ERROR - Parse error. missing ; before statement - static get default_data() { - ^ - -kfet.api.js:397: ERROR - Parse error. missing ; before statement - 'id': 0, 'trigramme': '', 'name': '', 'nickname': '', 'email': '', - ^ - -kfet.api.js:398: ERROR - Parse error. syntax error - 'is_cof' : false, 'promo': '', 'balance': 0, 'is_frozen': false, - ^ - -kfet.api.js:399: ERROR - Parse error. syntax error - 'departement': '', - ^ - -kfet.api.js:407: ERROR - Parse error. identifier is a reserved word - static get url_model() { return Urls['kfet.account'](); } - ^ - -kfet.api.js:407: ERROR - Parse error. syntax error - static get url_model() { return Urls['kfet.account'](); } - ^ - -kfet.api.js:414: ERROR - Parse error. missing ; before statement - static url_object_for(trigramme) { - ^ - -kfet.api.js:416: ERROR - Parse error. invalid return - return Urls['kfet.account.read'](trigramme_url); - ^ - -kfet.api.js:417: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:422: ERROR - Parse error. missing ; before statement - get api_pk() { return this.trigramme; } - ^ - -kfet.api.js:422: ERROR - Parse error. syntax error - get api_pk() { return this.trigramme; } - ^ - -kfet.api.js:427: ERROR - Parse error. syntax error - formatter() { - ^ - -kfet.api.js:429: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:433: ERROR - Parse error. missing ; before statement - get balance() { return this._balance; } - ^ - -kfet.api.js:433: ERROR - Parse error. syntax error - get balance() { return this._balance; } - ^ - -kfet.api.js:434: ERROR - Parse error. missing ; before statement - set balance(v) { return this._balance = floatCheck(v); } - ^ - -kfet.api.js:434: ERROR - Parse error. syntax error - set balance(v) { return this._balance = floatCheck(v); } - ^ - -kfet.api.js:439: ERROR - Parse error. missing ; before statement - get balance_ukf() { return amountToUKF(this.balance, this.is_cof); } - ^ - -kfet.api.js:439: ERROR - Parse error. syntax error - get balance_ukf() { return amountToUKF(this.balance, this.is_cof); } - ^ - -kfet.api.js:449: ERROR - Parse error. identifier is a reserved word -class Checkout extends APIModelObject { -^ - -kfet.api.js:456: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:458: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:466: ERROR - Parse error. missing ; before statement - static get default_data() { - ^ - -kfet.api.js:468: ERROR - Parse error. missing ; before statement - 'id': 0, 'name': '', 'balance': 0, 'valid_from': '', 'valid_to': '', - ^ - -kfet.api.js:476: ERROR - Parse error. identifier is a reserved word - static get url_model() { return ''; } - ^ - -kfet.api.js:476: ERROR - Parse error. syntax error - static get url_model() { return ''; } - ^ - -kfet.api.js:483: ERROR - Parse error. missing ; before statement - static url_object_for(api_pk) { - ^ - -kfet.api.js:485: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:490: ERROR - Parse error. syntax error - formatter() { - ^ - -kfet.api.js:492: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:496: ERROR - Parse error. missing ; before statement - get balance() { return this._balance; } - ^ - -kfet.api.js:496: ERROR - Parse error. syntax error - get balance() { return this._balance; } - ^ - -kfet.api.js:497: ERROR - Parse error. missing ; before statement - set balance(v) { this._balance = floatCheck(v); } - ^ - -kfet.api.js:497: ERROR - Parse error. syntax error - set balance(v) { this._balance = floatCheck(v); } - ^ - -kfet.api.js:507: ERROR - Parse error. identifier is a reserved word -class Statement extends ModelObject { -^ - -kfet.api.js:514: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:516: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:524: ERROR - Parse error. missing ; before statement - static get default_data() { - ^ - -kfet.api.js:526: ERROR - Parse error. missing ; before statement - 'id': 0, 'at': '', 'balance_old': 0, 'balance_new': 0, 'by': '', - ^ - -kfet.api.js:533: ERROR - Parse error. missing ; before statement - formatter() { - ^ - -kfet.api.js:535: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:539: ERROR - Parse error. missing ; before statement - get balance_old() { return this._balance_old; } - ^ - -kfet.api.js:539: ERROR - Parse error. syntax error - get balance_old() { return this._balance_old; } - ^ - -kfet.api.js:540: ERROR - Parse error. missing ; before statement - set balance_old(v) { this._balance_old = floatCheck(v); } - ^ - -kfet.api.js:540: ERROR - Parse error. syntax error - set balance_old(v) { this._balance_old = floatCheck(v); } - ^ - -kfet.api.js:542: ERROR - Parse error. missing ; before statement - get balance_new() { return this._balance_new; } - ^ - -kfet.api.js:542: ERROR - Parse error. syntax error - get balance_new() { return this._balance_new; } - ^ - -kfet.api.js:543: ERROR - Parse error. missing ; before statement - set balance_new(v) { this._balance_new = floatCheck(v); } - ^ - -kfet.api.js:543: ERROR - Parse error. syntax error - set balance_new(v) { this._balance_new = floatCheck(v); } - ^ - -kfet.api.js:545: ERROR - Parse error. missing ; before statement - get at() { return this._at; } - ^ - -kfet.api.js:545: ERROR - Parse error. syntax error - get at() { return this._at; } - ^ - -kfet.api.js:546: ERROR - Parse error. missing ; before statement - set at(v) { this._at = moment.isMoment(v) ? v : moment.tz(v, 'UTC'); } - ^ - -kfet.api.js:546: ERROR - Parse error. syntax error - set at(v) { this._at = moment.isMoment(v) ? v : moment.tz(v, 'UTC'); } - ^ - -kfet.api.js:555: ERROR - Parse error. identifier is a reserved word -class ArticleCategory extends ModelObject { -^ - -kfet.api.js:562: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:564: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:571: ERROR - Parse error. missing ; before statement - static get default_data() { - ^ - -kfet.api.js:572: ERROR - Parse error. missing ; before statement - return {'id': 0, 'name': ''}; - ^ - -kfet.api.js:578: ERROR - Parse error. missing ; before statement - formatter() { - ^ - -kfet.api.js:580: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:588: ERROR - Parse error. identifier is a reserved word -class Article extends ModelObject { -^ - -kfet.api.js:594: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:596: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:604: ERROR - Parse error. missing ; before statement - static get default_data() { - ^ - -kfet.api.js:606: ERROR - Parse error. missing ; before statement - 'id': 0, 'name': '', 'price': 0, 'stock': 0, - ^ - -kfet.api.js:607: ERROR - Parse error. syntax error - 'category': new ArticleCategory(), - ^ - -kfet.api.js:614: ERROR - Parse error. missing ; before statement - formatter() { - ^ - -kfet.api.js:616: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:620: ERROR - Parse error. missing ; before statement - get price() { return this._price; } - ^ - -kfet.api.js:620: ERROR - Parse error. syntax error - get price() { return this._price; } - ^ - -kfet.api.js:621: ERROR - Parse error. missing ; before statement - set price(v) { this._price = floatCheck(v); } - ^ - -kfet.api.js:621: ERROR - Parse error. syntax error - set price(v) { this._price = floatCheck(v); } - ^ - -kfet.api.js:640: ERROR - Parse error. identifier is a reserved word -class Formatter { -^ - -kfet.api.js:642: ERROR - Parse error. missing ; before statement - static get props() { return []; } - ^ - -kfet.api.js:642: ERROR - Parse error. syntax error - static get props() { return []; } - ^ - -kfet.api.js:643: ERROR - Parse error. missing ; before statement - static get attrs() { return []; } - ^ - -kfet.api.js:643: ERROR - Parse error. syntax error - static get attrs() { return []; } - ^ - -kfet.api.js:653: ERROR - Parse error. missing ; before statement - static get(object, name, prefix) { - ^ - -kfet.api.js:654: ERROR - Parse error. syntax error - prefix = prefix || ''; - ^ - -kfet.api.js:657: ERROR - Parse error. invalid return - return this[method](object); - ^ - -kfet.api.js:658: ERROR - Parse error. invalid return - return object[name]; - ^ - -kfet.api.js:659: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:665: ERROR - Parse error. missing ; before statement - static get_prop(object, name) { - ^ - -kfet.api.js:667: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:673: ERROR - Parse error. missing ; before statement - static get_attr(obj, attr) { - ^ - -kfet.api.js:675: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:689: ERROR - Parse error. missing ; before statement - static render(object, $container, options) { - ^ - -kfet.api.js:690: ERROR - Parse error. syntax error - options.props = options.props || []; - ^ - -kfet.api.js:711: ERROR - Parse error. invalid return - return $container; - ^ - -kfet.api.js:712: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:721: ERROR - Parse error. identifier is a reserved word -class AccountFormatter extends Formatter { -^ - -kfet.api.js:727: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:729: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:735: ERROR - Parse error. missing ; before statement - static get attrs() { - ^ - -kfet.api.js:737: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:739: ERROR - Parse error. missing ; before statement - static get _data_balance() { - ^ - -kfet.api.js:741: ERROR - Parse error. missing ; before statement - 'default': '', 'frozen': 'frozen', - ^ - -kfet.api.js:742: ERROR - Parse error. syntax error - 'ok': 'ok', 'low': 'low', 'neg': 'neg', - ^ - -kfet.api.js:749: ERROR - Parse error. identifier is a reserved word - static prop_balance(a) { - ^ - -kfet.api.js:751: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:756: ERROR - Parse error. missing ; before statement - static prop_is_cof(a) { - ^ - -kfet.api.js:758: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:764: ERROR - Parse error. missing ; before statement - static attr_data_balance(a) { - ^ - -kfet.api.js:765: ERROR - Parse error. missing ; before statement - if (a.is_frozen) { return this._data_balance.frozen; } - ^ - -kfet.api.js:765: ERROR - Parse error. syntax error - if (a.is_frozen) { return this._data_balance.frozen; } - ^ - -kfet.api.js:766: ERROR - Parse error. invalid return - else if (a.balance >= 5) { return this._data_balance.ok; } - ^ - -kfet.api.js:767: ERROR - Parse error. invalid return - else if (a.balance >= 0) { return this._data_balance.low; } - ^ - -kfet.api.js:768: ERROR - Parse error. invalid return - else /* a.balance < 0 */ { return this._data_balance.neg; } - ^ - -kfet.api.js:769: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:778: ERROR - Parse error. identifier is a reserved word -class LIQFormatter extends AccountFormatter { -^ - -kfet.api.js:784: ERROR - Parse error. missing ; before statement - static get_prop() { - ^ - -kfet.api.js:786: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:791: ERROR - Parse error. missing ; before statement - static attr_data_balance(a) { return this._data_balance.ok; } - ^ - -kfet.api.js:791: ERROR - Parse error. syntax error - static attr_data_balance(a) { return this._data_balance.ok; } - ^ - -kfet.api.js:800: ERROR - Parse error. identifier is a reserved word -class CheckoutFormatter extends Formatter { -^ - -kfet.api.js:806: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:808: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:813: ERROR - Parse error. missing ; before statement - static prop_balance(c) { - ^ - -kfet.api.js:815: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:825: ERROR - Parse error. identifier is a reserved word -class StatementFormatter extends Formatter { -^ - -kfet.api.js:831: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:833: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:838: ERROR - Parse error. missing ; before statement - static prop_balance_old(s) { - ^ - -kfet.api.js:840: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:845: ERROR - Parse error. missing ; before statement - static prop_balance_new(s) { - ^ - -kfet.api.js:847: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:852: ERROR - Parse error. missing ; before statement - static prop_at(s) { - ^ - -kfet.api.js:854: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:864: ERROR - Parse error. identifier is a reserved word -class ArticleCategoryFormatter extends Formatter { -^ - -kfet.api.js:870: ERROR - Parse error. missing ; before statement - static get props() { - ^ - -kfet.api.js:872: ERROR - Parse error. syntax error - } - ^ - -kfet.api.js:874: ERROR - Parse error. missing ; before statement - static get _data_stock() { - ^ - -kfet.api.js:876: ERROR - Parse error. missing ; before statement - 'default': '', 'low': 'low', - ^ - -kfet.api.js:877: ERROR - Parse error. syntax error - 'ok': 'ok', 'neg': 'neg', - ^ - -kfet.api.js:881: ERROR - Parse error. identifier is a reserved word - static attr_data_stock(a) { - ^ - -kfet.api.js:882: ERROR - Parse error. missing ; before statement - if (a.stock >= 5) { return this._data_stock.ok; } - ^ - -kfet.api.js:882: ERROR - Parse error. syntax error - if (a.stock >= 5) { return this._data_stock.ok; } - ^ - -kfet.api.js:883: ERROR - Parse error. invalid return - else if (a.stock >= -5) { return this._data_stock.low; } - ^ - -kfet.api.js:884: ERROR - Parse error. invalid return - else /* a.stock < -5 */ { return this._data_stock.neg; } - ^ - -kfet.api.js:885: ERROR - Parse error. syntax error - } - ^ - -223 error(s), 0 warning(s) From d5dfd5fa9349083a212f031ea2b397eb763155a1 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 7 Mar 2017 18:36:56 -0300 Subject: [PATCH 05/38] move ModelList def --- kfet/static/kfet/js/kfet.api.js | 319 +++++++++++++++++--------------- 1 file changed, 171 insertions(+), 148 deletions(-) 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; + } +} + /* ---------- ---------- */ /** From a05a075962e6bf11439ef059d7a601ada0d9f94b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 8 Mar 2017 10:47:51 -0300 Subject: [PATCH 06/38] apimodellist & articlelist --- kfet/static/kfet/js/kfet.api.js | 125 ++++++++++++++++++++++++++------ 1 file changed, 104 insertions(+), 21 deletions(-) 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']; + } + + + /* ---------- ---------- */ /** From fe8e5d7e464c1181fa08b5205430f27fbcd21c3d Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 9 Mar 2017 09:20:23 -0300 Subject: [PATCH 07/38] move and adapt manager and completion --- kfet/static/kfet/js/kpsul.js | 226 ++++++++++++ kfet/templates/kfet/kpsul.html | 612 +-------------------------------- 2 files changed, 235 insertions(+), 603 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 9dd6ae19..238a40a6 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -4,6 +4,7 @@ class KPsulManager { this._env = env; this.account_manager = new AccountManager(this); this.checkout_manager = new CheckoutManager(this); + this.article_manager = new ArticleManager(this); } reset(soft) { @@ -367,3 +368,228 @@ class CheckoutSelection { } } +class ArticleManager { + + constructor(env) { + this._env = env; // Global K-Psul Manager + + this._$container = $('#articles_data tbody'); + this._$input = $('#article_autocomplete'); + this._$nb = $('#article_number'); + this.templates = {'category': '', + 'article' : ''} + + this.selected = new Article() ; + this.list = new ArticleList() ; + this.autocomplete = new ArticleAutocomplete(this); + + this._init_events(); + } + + get nb() { + return this._$nb.val() ; + } + + display_list() { + this.list.display(this._$container, this.templates) ; + } + + validate(article) { + this.selected.from(article) ; + this._$input.val(article.name); + this._$nb.val('1'); + this._$nb.focus().select(); + } + + unset() { + this.selected.clear(); + } + + is_empty() { + return this.selected.is_empty(); + } + + reset_data() { + this._$container.find('tr').remove(); + this.list.clear(); + this.list.fromAPI({}, this.display_list.bind(this), $.noop) ; + } + + update_data(data) { + for (let article_dict of data) { + article = this.list.find(Article, {'id': article_dict['id']}); + + // For now, article additions are disregarded + if (article) { + article.stock = article_dict['stock']; + this._$container.find('#data-article-'+article_dict['id']+' .stock') + .text(article_dict['stock']); + } + } + } + + reset() { + this.unset() ; + this._$nb.val(''); + this._$input.val(''); + this.autocomplete.showAll() ; + } + + _init_events() { + var that = this; + + // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 + var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; + var arrowKeys = /^(37|38|39|40)$/; + + //Global input event (to merge ?) + this._$input.on('keydown', function(e) { + if (e.keyCode == 13 && that._$input.val() == '') { + kpsul._env.performOperations(); + } + }); + + this._$container.on('click', '.article', function() { + var id = $(this).attr('data-article-id') ; + var article = that.list.find(Article, { 'id': intCheck(id) }); + if (article) + that.validate(article); + }); + + this._$nb.on('keydown', function(e) { + if (e.keyCode == 13 && that.constructor.check_nb(that.nb) && !that.is_empty()) { + kpsul._env.addPurchase(that.selected, that.nb); + that.reset(); + that.focus(); + } + if (normalKeys.test(e.keyCode) || arrowKeys.test(e.KeyCode) || e.ctrlKey) { + if (e.ctrlKey && e.charCode == 65) + that._$nb.val(''); + return true ; + } + if (that.constructor.check_nb(that.nb+e.key)) + return true; + return false; + + }); + } + + focus() { + this._$input.focus(); + return this; + } + + static check_nb(nb) { + return /^[0-9]+$/.test(nb) && nb > 0 && nb <= 24 ; + } +} + +class ArticleAutocomplete { + + constructor(article_manager) { + this.manager = article_manager; + this.matching = []; + this.active_categories = []; + this._$container = article_manager._$container ; + this._$input = $('#article_autocomplete'); + + this.showAll() ; + this._init_events(); + } + + _init_events() { + var that = this ; + + // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 + var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; + + this._$input + .on('keydown', function(e) { + var text = that._$input.val() ; + if (normalKeys.test(e.keyCode) || e.ctrlKey) { + // For the backspace key, we suppose the cursor is at the very end + if(e.keyCode == 8) { + that.update(text.substring(0, text.length-1), true); + } + return true ; + } + that.update(text+e.key, false); + + return false ; + + }); + + } + + update(prefix, backspace) { + + var article_list = this.manager.list ; + var lower = prefix.toLowerCase() ; + var that = this ; + this.matching = article_list.data['article'] + .filter(function(article) { + return article.name.toLowerCase() + .indexOf(lower) === 0 ; + }); + + this.active_categories = article_list.data['category'] + .filter(function(category) { + return that.matching.find(function(article) { + return article.category === category ; + }); + }); + + if (this.matching.length == 1) { + if (!backspace) { + this.manager.validate(this.matching[0]) ; + this.showAll() ; + } else { + this.manager.unset(); + this.updateDisplay(); + } + } else if (this.matching.length > 1) { + this.manager.unset(); + this.updateDisplay() ; + if (!backspace) + this.updatePrefix(); + } + } + + updateDisplay() { + var article_list = this.manager.list ; + for (let article of article_list.data['article']) { + if (this.matching.indexOf(article) > -1) { + this._$container.find('[data-article-id='+article.id+']').show(); + } else { + this._$container.find('[data-article-id='+article.id+']').hide(); + } + } + + for (let category of article_list.data['category']) { + if (this.active_categories.indexOf(category) > -1) { + this._$container.find('[data-category-id='+category.id+']').show(); + } else { + this._$container.find('[data-category-id='+category.id+']').hide(); + } + } + } + + updatePrefix() { + var lower = this.matching.map(function (article) { + return article.name.toLowerCase() ; + }); + + lower.sort() ; + var first = lower[0], last = lower[lower.length-1], + length = first.length, i = 0; + while (i < length && first.charAt(i) === last.charAt(i)) i++; + + this._$input.val(first.substring(0,i)) ; + } + + showAll() { + this.matching = this.manager.list.data['article']; + this.active_categories = this.manager.list.data['category']; + this.updateDisplay(); + } +} diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 6454afa9..05dff009 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -195,398 +195,6 @@ function functionCheck(v) { return function(){}; } -function restrict(obj, attr_list) { - var restricted = {} ; - for (let attr of attr_list) { - restricted[attr] = obj[attr] ; - } - return restricted ; -} - -class ArticleCategory { - - constructor(id, name) { - this.id = id; - this.name = name; - } - - get id() { return this._id; } - - set id(v) { this._id = intCheck(v); } - - html(template) { - var $template = $(template) - $template.attr('id', 'data-category-'+this.id); - $template.find('td').text(this.name); - return $template ; - } - - static compare(a, b) { - return a.name.localeCompare(b.name) ; - } -} - -class Article { - - constructor () { - $.extend(this, this.constructor.default_data); - } - - static get default_data() { - return { - 'id': 0, 'name': '', 'price': 0, 'stock': 0, - 'category': new ArticleCategory(), - }; - } - - get id() { return this._id; } - get price() { return this._price; } - get stock() { return this._stock; } - - set id(v) { this._id = intCheck(v); } - set price(v) { this._price = floatCheck(v); } - set stock(v) { this._stock = intCheck(v); } - - get str_price_ukf() { - return amountToUKF(this.price, false); - } - - static get _data_stock_ok() { return ''; } - static get _data_stock_low() { return 'low'; } - static get _data_stock_neg() { return 'neg'; } - - get data_stock() { - var stock = this.stock ; - if (stock >= 5) { return this.constructor._data_stock_ok; } - else if (stock >= -5) { return this.constructor._data_stock_low; } - else /* stock < -5 */ { return this.constructor._data_stock_neg; } - } - - from(data) { - $.extend(this, this.constructor.default_data, data); - } - - html(template) { - var $template = $(template); - $template - .find('.name').text(this.name).end() - .find('.price').text(this.str_price_ukf).end() - .find('.stock').text(this.stock).end(); - $template.attr('id', 'data-article-'+this.id); - $template.attr('data-stock', this.data_stock); - return $template ; - } - - static compare(a, b) { - return a.name.localeCompare(b.name) ; - } - - reset() { - this.from({}); - } -} - -class ArticleList { - constructor() { - this.articles = []; - this.categories = []; - } - - get_or_create(id, name) { - var category = this.categories.find(c => c.id === id); - if (!category) { - category = new ArticleCategory(id, name); - this.categories.push(category); - } - return category; - } - - from(data, callback) { - callback = functionCheck(callback); - - for (let article_data of data['articles']) { - var category = this.get_or_create(article_data['category_id'], article_data['category__name']) ; - article_data = restrict(article_data, ['name', 'price', 'stock', 'id']) ; - article_data['category'] = category ; - - var article = new Article() ; - article.from(article_data) ; - this.articles.push(article) ; - } - - callback() ; - } - - fromAPI(on_success, on_error) { - on_error = functionCheck(on_error); - var that = this ; - $.ajax({ - dataType: "json", - url : "{% url 'kfet.kpsul.articles_data' %}", - method : "GET", - }) - .done((data) => this.from(data, on_success)) - .fail(on_error); - } - - display($container, $article_template, $category_template) { - this.categories.sort(ArticleCategory.compare) ; - for (let cat of this.categories) { - var cat_articles = this.articles.filter(a => a.category.id === cat.id) ; - cat_articles.sort(Article.compare); - - $container.append(cat.html($category_template)) ; - for (let art of cat_articles) { - $container.append(art.html($article_template)) ; - } - } - } - - clear() { - this.articles = []; - this.categories = [] ; - } - - find_by_id(name) { - return this.articles.find(function(a) { - return a.name === name ; - }); - } - - get_from_elt($elt) { - var id = $elt.attr('id').split('-')[2]; - - return this.articles.find(function(article) { - return (article.id == id) ; - }); - } -} - -class ArticleManager { - - constructor(env) { - this._env = env; // Global K-Psul Manager - - this._$container = $('#articles_data tbody'); - this._$input = $('#article_autocomplete'); - this._$nb = $('#article_number'); - this._category_template = ''; - this._article_template = ''; - - this.selected = new Article() ; - this.list = new ArticleList() ; - this.autocomplete = new ArticleAutocomplete(this); - - this._init_events(); - } - - get nb() { - return this._$nb.val() ; - } - - display_list() { - this.list.display(this._$container, this._article_template, this._category_template) ; - } - - validate(article) { - this.selected.from(article) ; - this._$input.val(article.name); - this._$nb.val('1'); - this._$nb.focus().select(); - } - - unset() { - this.selected.reset(); - } - - is_empty() { - return this.selected.id == 0 ; - } - - reset_data() { - this._$container.find('tr').remove(); - this.list.clear(); - this.list.fromAPI(this.display_list.bind(this)) ; - } - - update_data(data) { - for (let article_dict of data) { - var article = this.list.articles.find(function(art) { - return (art.id == article_dict['id']); - }); - - // For now, article additions are disregarded - if (article) { - article.stock = article_dict['stock']; - this._$container.find('#data-article-'+article_dict['id']+' .stock') - .text(article_dict['stock']); - } - } - } - - reset() { - this.unset() ; - this._$nb.val(''); - this._$input.val(''); - this.autocomplete.showAll() ; - } - - _init_events() { - var that = this; - - // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 - var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; - var arrowKeys = /^(37|38|39|40)$/; - - //Global input event (to merge ?) - this._$input.on('keydown', function(e) { - if (e.keyCode == 13 && that._$input.val() == '') { - that._env.performOperations(); - } - }); - - this._$container.on('click', '.article', function() { - var article = that.list.get_from_elt($(this)) ; - that.validate(article); - }); - - this._$nb.on('keydown', function(e) { - if (e.keyCode == 13 && ArticleManager.check_nb(that.nb) && !that.is_empty()) { - that._env.addPurchase(that.selected, that.nb); - that.reset(); - that.focus(); - } - if (normalKeys.test(e.keyCode) || arrowKeys.test(e.KeyCode) || e.ctrlKey) { - if (e.ctrlKey && e.charCode == 65) - that._$nb.val(''); - return true ; - } - if (ArticleManager.check_nb(that.nb+e.key)) - return true; - return false; - - }); - } - - focus() { - this._$input.focus(); - return this; - } - - static check_nb(nb) { - return /^[0-9]+$/.test(nb) && nb > 0 && nb <= 24 ; - } -} - -class ArticleAutocomplete { - - constructor(article_manager) { - this.manager = article_manager; - this.matching = []; - this.active_categories = []; - this._$container = article_manager._$container ; - this._$input = $('#article_autocomplete'); - - this.showAll() ; - this._init_events(); - } - - _init_events() { - var that = this ; - - // 8:Backspace|9:Tab|13:Enter|46:DEL|112-117:F1-6|119-123:F8-F12 - var normalKeys = /^(8|9|13|46|112|113|114|115|116|117|119|120|121|122|123)$/; - - this._$input - .on('keydown', function(e) { - var text = that._$input.val() ; - if (normalKeys.test(e.keyCode) || e.ctrlKey) { - // For the backspace key, we suppose the cursor is at the very end - if(e.keyCode == 8) { - that.update(text.substring(0, text.length-1), true); - } - return true ; - } - that.update(text+e.key, false); - - return false ; - - }); - - } - - update(prefix, backspace) { - - var article_list = this.manager.list ; - var lower = prefix.toLowerCase() ; - var that = this ; - this.matching = article_list.articles.filter(function(article) { - return article.name.toLowerCase() - .indexOf(lower) === 0 ; - }); - - this.active_categories = article_list.categories.filter(function(category) { - return that.matching.find(function(article) { - return article.category === category ; - }); - }); - - if (this.matching.length == 1) { - if (!backspace) { - this.manager.validate(this.matching[0]) ; - this.showAll() ; - } else { - this.manager.unset(); - this.updateDisplay(); - } - } else if (this.matching.length > 1) { - this.manager.unset(); - this.updateDisplay() ; - if (!backspace) - this.updatePrefix(); - } - } - - updateDisplay() { - var article_list = this.manager.list ; - for (let article of article_list.articles) { - if (this.matching.indexOf(article) > -1) { - this._$container.find('#data-article-'+article.id).show(); - } else { - this._$container.find('#data-article-'+article.id).hide(); - } - } - - for (let category of article_list.categories) { - if (this.active_categories.indexOf(category) > -1) { - this._$container.find('#data-category-'+category.id).show(); - } else { - this._$container.find('#data-category-'+category.id).hide(); - } - } - } - - updatePrefix() { - var lower = this.matching.map(function (article) { - return article.name.toLowerCase() ; - }); - - lower.sort() ; - var first = lower[0], last = lower[lower.length-1], - length = first.length, i = 0; - while (i < length && first.charAt(i) === last.charAt(i)) i++; - - this._$input.val(first.substring(0,i)) ; - } - - showAll() { - this.matching = this.manager.list.articles; - this.active_categories = this.manager.list.categories; - this.updateDisplay(); - } -} - - $(document).ready(function() { 'use strict'; // ----- @@ -748,206 +356,11 @@ $(document).ready(function() { // Articles data // ----- - var articles_container = $('#articles_data tbody'); - var article_category_default_html = ''; - var article_default_html = ''; - - function addArticle(article) { - var article_html = $(article_default_html); - article_html.attr('id', 'data-article-'+article['id']); - article_html.addClass('data-category-'+article['category_id']); - for (var elem in article) { - article_html.find('.'+elem).text(article[elem]) - } - article_html.find('.price').text(amountToUKF(article['price'], false)); - var category_html = articles_container - .find('#data-category-'+article['category_id']); - if (category_html.length == 0) { - category_html = $(article_category_default_html); - category_html.attr('id', 'data-category-'+article['category_id']); - category_html.find('td').text(article['category__name']); - var added = false; - articles_container.find('.category').each(function() { - if (article['category__name'].toLowerCase() < $(this).text().toLowerCase()) { - $(this).before(category_html); - added = true; - return false; - } - }); - if (!added) articles_container.append(category_html); - } - var $after = articles_container.find('#data-category-'+article['category_id']); - articles_container - .find('.article.data-category-'+article['category_id']).each(function() { - if (article['name'].toLowerCase < $('.name', this).text().toLowerCase()) - return false; - $after = $(this); - }); - $after.after(article_html); - // Pour l'autocomplétion - articlesList.push([article['name'],article['id'],article['category_id'],article['price']]); - } - - function getArticles() { - $.ajax({ - dataType: "json", - url : "{% url 'kfet.kpsul.articles_data' %}", - method : "GET", - }) - .done(function(data) { - for (var i=0; i -1) { - articles_container.find('#data-article-'+articlesList[i][1]).show(); - if (categories_to_display.indexOf(articlesList[i][2]) == -1) - categories_to_display.push(articlesList[i][2]); - } else { - articles_container.find('#data-article-'+articlesList[i][1]).hide(); - } - } - articles_container.find('.category').hide(); - for (var i=0; i 1) { - articleId.val(0); - if (commit) - articleSelect.val(sharedPrefix(articlesMatch)); - displayMatchedArticles(articlesMatch); - } - return false; - } - - // A utiliser après la sélection d'un article - function goToArticleNb() { - articleNb.val('1'); - articleNb.focus().select(); - } - - articleSelect.on('keydown', function(e) { - var text = articleSelect.val(); - // Comportement normal pour ces touches - if (normalKeys.test(e.keyCode) || e.ctrlKey) { - if (text == '' && e.keyCode == 13) - performOperations(); - if (e.keyCode == 8) - updateMatchedArticles(text.substring(0,text.length-1), false); - if (e.charCode == 65 && e.ctrlKey) { - articleId.val(0); - articleSelect.val(''); - } - return true; - } - if (updateMatchedArticles(text+e.key)) - goToArticleNb(); - return false; - }); - - function getArticleId($article) { - return $article.attr('id').split('-')[2]; - } - - function getArticleName($article) { - return $article.find('.name').text(); - } - - // Sélection des articles à la souris/tactile - articles_container.on('click', '.article', function() { - articleId.val(getArticleId($(this))); - articleSelect.val(getArticleName($(this))); - displayMatchedArticles(articlesList); - goToArticleNb(); - }); - - function is_nb_ok(nb) { - return /^[0-9]+$/.test(nb) && nb > 0 && nb <= 24; - } - - articleNb.on('keydown', function(e) { - if (e.keyCode == 13 && is_nb_ok(articleNb.val()) && articleId.val() > 0) { - addPurchase(articleId.val(), articleNb.val()); - articleSelect.val(''); - articleNb.val(''); - articleSelect.focus(); - displayMatchedArticles(articlesList); - return false; - } - if (normalKeys.test(e.keyCode) || arrowKeys.test(e.keyCode) || e.keyCode == 8 || e.ctrlKey) { - if (e.ctrlKey && e.charCode == 65) - articleNb.val(''); - return true; - } - var nb = articleNb.val()+e.key; - if (is_nb_ok(nb)) - return true; - return false; - }); - // ----- // Basket // ----- @@ -956,8 +369,8 @@ $(document).ready(function() { var basket_container = $('#basket table'); var arrowKeys = /^(37|38|39|40)$/; - function amountEuroPurchase(article_data, nb) { - var amount_euro = - article_data[3] * nb ; + function amountEuroPurchase(article, nb) { + var amount_euro = - article.price * nb ; if (Config.get('addcost_for') && Config.get('addcost_amount') && account_manager.account.trigramme != Config.get('addcost_for')) amount_euro -= Config.get('addcost_amount') * nb; var reduc_divisor = 1; @@ -966,19 +379,15 @@ $(document).ready(function() { return amount_euro / reduc_divisor; } - function addPurchase(id, nb) { + function addPurchase(article, nb) { - var i = 0; - while (i Date: Thu, 9 Mar 2017 09:20:53 -0300 Subject: [PATCH 08/38] articlelist and modellist finished --- kfet/static/kfet/js/kfet.api.js | 56 ++++++++++++++++++++++++--------- 1 file changed, 42 insertions(+), 14 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 9beefbb6..4747dfce 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -585,7 +585,7 @@ class ModelList { */ static get names() { return this.models.map(function(v) { - return v.constructor.verbose_name; + return v.verbose_name; }); } @@ -594,6 +594,7 @@ class ModelList { * @param {Object[]} [datalist=[]] */ constructor(datalist) { + this.data = {}; this.from(datalist || []); } @@ -606,7 +607,7 @@ class ModelList { */ get_or_create(depth, data) { var model = this.constructor.models[depth]; - var name = model.constructor.verbose_name ; + var name = model.verbose_name ; var existing = this.data[name].find(function (v){ return v.id === data['id'] ; @@ -616,12 +617,13 @@ class ModelList { return existing; } - if (depth == this.constructor.models.length) { + if (depth == this.constructor.models.length-1) { var created = new model(data) ; + this.data[name].push(created); return created ; } else { var par_name = this.constructor.models[depth+1] - .constructor.verbose_name; + .verbose_name; var par_data = data[par_name]; var created = new model(data); @@ -645,7 +647,7 @@ class ModelList { } for (let data of datalist) { - this.get_or_create(data, 0); + this.get_or_create(0, data); } } @@ -665,21 +667,25 @@ class ModelList { */ render_element(elt, templates, options) { var name = elt.constructor.verbose_name; - var depth = this.names.indexOf(name); + var depth = this.constructor.names.indexOf(name); var template = templates[name]; + var options = options || {} ; if (depth == -1) { return $(); } else if (depth == 0) { - return elt.display($(template), options); + 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); - $container = elt.display($(template), options); - $container.attr('data'+name+'id', elt.id); + var $container = $('
'); + $container.attr('data-'+name+'-id', elt.id); + $container.append(elt.display($(template), options)); for (let child of children) { $container.append(this.render_element(child, templates, options)); @@ -701,7 +707,7 @@ class ModelList { roots.sort(root_model.compare); for (let root of roots) { - $container.append(this.render_element(root, templates, options); + $container.append(this.render_element(root, templates, options)); } return $container; @@ -758,7 +764,7 @@ class APIModelList extends ModelList { api_options['format'] = 'json'; - $.getJSON(this.url_model, api_options) + $.getJSON(this.constructor.url_model, api_options) .done(function(json, textStatus, jqXHR) { that.from(json); on_success(json, textStatus, jqXHR); @@ -790,9 +796,10 @@ class ArticleList extends APIModelList { * @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']; + static get url_model() { + return Urls['kfet.kpsul.articles_data'](); } +} @@ -1040,11 +1047,32 @@ class ArticleCategoryFormatter extends Formatter { /** * Properties renderable to html. - * @default {@link Models.Statement.props} + * @default {@link Models.ArticleCategory.props} */ static get props() { return ArticleCategory.props; } +} + + +/** + * @memberof Formatters + * @extends Formatters.Formatter + */ + +class ArticleFormatter extends Formatter { + + /** + * Properties renderable to html. + * @default {@link Models.Article.props} + */ + static get props() { + return Article.props; + } + + static prop_price(s) { + return amountToUKF(s.price, true); + } static get _data_stock() { return { From 8aa4fa2dceb224a256450577c583841ab2dcfd63 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 9 Mar 2017 09:21:07 -0300 Subject: [PATCH 09/38] modify article API return --- kfet/views.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 26ad88b4..4b356d43 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1338,13 +1338,27 @@ def history_json(request): opegroups_list.append(opegroup_dict) return JsonResponse({ 'opegroups': opegroups_list }) + @teamkfet_required def kpsul_articles_data(request): articles = ( Article.objects - .values('id', 'name', 'price', 'stock', 'category_id', 'category__name') - .filter(is_sold=True)) - return JsonResponse({ 'articles': list(articles) }) + .filter(is_sold=True) + .select_related('category')) + articlelist = [] + + for article in articles: + articlelist.append({ + 'id': article.id, + 'name': article.name, + 'price': article.price, + 'stock': article.stock, + 'category': { + 'id': article.category.id, + 'name': article.category.name, + } + }) + return JsonResponse(articlelist, safe=False) @teamkfet_required def history(request): From e1abff224210c6957756ce1237deef784fded4a4 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 9 Mar 2017 22:31:59 -0300 Subject: [PATCH 10/38] last tweaks --- kfet/static/kfet/js/kfet.api.js | 10 ++++++---- kfet/templates/kfet/kpsul.html | 1 + 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 4747dfce..2a0c398b 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -683,15 +683,17 @@ class ModelList { .filter(v => v[name].id == elt.id) ; children.sort(child_model.compare); + //TODO: less dirty var $container = $('
'); - $container.attr('data-'+name+'-id', elt.id); - $container.append(elt.display($(template), options)); + var $elt = elt.display($(template), options); + $elt.attr('data-'+name+'-id', elt.id); + $container.append($elt); for (let child of children) { $container.append(this.render_element(child, templates, options)); } - return $container; + return $container.html(); } } @@ -719,7 +721,7 @@ class ModelList { * @param {Object} props Properties to match */ find(model, props) { - if (!this.constructor.models.find(model)) { + if (this.constructor.models.indexOf(model) == -1) { return undefined ; } diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 05dff009..43a55dd2 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -915,6 +915,7 @@ $(document).ready(function() { var env = { articleSelect: articleSelect, + addPurchase: addPurchase, updateBasketAmount: updateBasketAmount, updateBasketRel: updateBasketRel, performOperations: performOperations, From 02485afd9ba652ac3dc6697b96354d75bfbc2120 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 10 Mar 2017 19:59:15 -0300 Subject: [PATCH 11/38] doc and compare function --- kfet/static/kfet/js/kfet.api.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 2a0c398b..81f0cfe4 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -547,17 +547,25 @@ class Article extends ModelObject { /** * Verbose name for Article model * @default 'article' - * @see {@link Models.ModelObject.compare|ModelObject.compare} + * @see {@link Models.ModelObject.verbose_name|ModelObject.verbose_name} */ static get verbose_name() { return 'article'; } /** - * @default {@link Formatters.ArticleCategoryFormatter} + * @default {@link Formatters.ArticleFormatter} */ formatter() { return ArticleFormatter; } + /** + * Comparison function between Article model instances. + * @see {@link Models.ModelObject.compare|ModelObject.compare} + */ + static compare(a, b) { + return a.name.localeCompare(b.name); + } + // Take care of 'price' type // API currently returns a string object (serialization of Decimal type within Django) get price() { return this._price; } From 0219d998ac97b44a51a04f1bc3e5db9e2a6f98f1 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 15 Mar 2017 02:45:13 -0300 Subject: [PATCH 12/38] model tree struct draft --- kfet/static/kfet/js/kfet.api.js | 92 ++++++++++++++++----------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 81f0cfe4..e0bc2c35 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -572,75 +572,74 @@ class Article extends ModelObject { set price(v) { this._price = floatCheck(v); } } +class TreeNode { + + constructor(type, content) { + this.type = type; + this.content = content; + this.parent = null; + this.children = []; + } +} + /** * Simple {@link Models.ModelObject} list. * @memberof Models */ -class ModelList { +class ModelTree { /** * Nested structure of the list * @abstract * @type {Models.ModelObject[]} */ - static get models() { return []; } + static get models() { return {}; } - /** - * Verbose names for list models - * @abstract - * @type {string[]} - */ - static get names() { - return this.models.map(function(v) { - return v.verbose_name; - }); - } /** * Creates empty instance and populates it with data if given * @param {Object[]} [datalist=[]] */ constructor(datalist) { - this.data = {}; + this._root = new TreeNode({}) ; 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. + * 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 */ - get_or_create(depth, data) { - var model = this.constructor.models[depth]; - var name = model.verbose_name ; - - var existing = this.data[name].find(function (v){ - return v.id === data['id'] ; - }) ; + get_or_create(data, direction=0) { + var model = this.constructor.models[data.type]; + var existing = this.find(data.type, data.content.id); if (existing) { return existing; } - if (depth == this.constructor.models.length-1) { - var created = new model(data) ; - this.data[name].push(created); - return created ; - } else { - var par_name = this.constructor.models[depth+1] - .verbose_name; + var content = new this.constructor.models[data.type](); + var node = new TreeNode(data.type, content); - 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 ; + if (direction <= 0) { + var parent = data.parent ? this.get_or_create(data.parent, -1) : this._root; + node.parent = parent; + parent.children.push(node); } + + if (direction >= 0) { + for (let child_data of data.children) { + var child = this.get_or_create(child_data, 1); + child.parent = node; + node.children.push(child); + } + } + + return node ; } /** @@ -655,7 +654,7 @@ class ModelList { } for (let data of datalist) { - this.get_or_create(0, data); + this.get_or_create(data, 0); } } @@ -728,18 +727,19 @@ class ModelList { * @param {class} model * @param {Object} props Properties to match */ - find(model, props) { - if (this.constructor.models.indexOf(model) == -1) { - return undefined ; - } + find(type, id) { + (function recurse(node) { + if (node.type === type && node.data.id === id) + return node ; - return this.data[model.verbose_name].find(function(v) { - for (let key in props) { - if (v[key] !== props[key]) - return false; + for (let child of node.children) { + var result = recurse(child) ; + if (result) + return result; } - return true; - }); + + return null; + })(this._root;) } } From 1570d9f49446e6939a786dd27d4471d78004741b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 15 Mar 2017 22:10:56 -0300 Subject: [PATCH 13/38] Polish ModelForest class --- kfet/static/kfet/js/kfet.api.js | 177 ++++++++++++++++---------------- 1 file changed, 90 insertions(+), 87 deletions(-) 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 = $('
'); + $container.attr('id', node.type+'-'+node.content.id); - //TODO: less dirty - var $container = $('
'); - var $elt = elt.display($(template), options); - $elt.attr('data-'+name+'-id', elt.id); - $container.append($elt); + var $rendered = node.content.display($(template), options); + $container.append($rendered); - for (let child of children) { - $container.append(this.render_element(child, templates, options)); - } + //TODO: better sorting control + node.children.sort(ModelObject.compare); - return $container.html(); + for (let child of node.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 first_missing = node; + + while (existing && !($container.find('#'+existing.type+'-'+existing.id))) { + first_missing = existing ; + existing = existing.parent; + } + + var $to_insert = render_element(first_missing, templates, options); + var $insert_in = existing ? $container.find('#'+existing.type+'-'+existing.id) + : $container ; + $insert_in.prepend($to_insert); } /** @@ -711,9 +707,7 @@ class ModelTree { * @param {Object} [options] Options for element render method */ 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); + this.roots.sort(ModelObject.compare); for (let root of roots) { $container.append(this.render_element(root, templates, options)); @@ -728,28 +722,35 @@ class ModelTree { * @param {Object} props Properties to match */ find(type, id) { - (function recurse(node) { + + function recurse(node) { if (node.type === type && node.data.id === id) return node ; for (let child of node.children) { - var result = recurse(child) ; - if (result) + if (result = recurse(node)) return result; } return null; - })(this._root;) + } + + for (let root of this.roots) { + if (result = recurse(root)) + return result; + } + + return null ; } } /** * Describes a model list that can be filled through API. - * @extends Models.ModelList + * @extends Models.ModelForest * @memberof Models */ -class APIModelList extends ModelList { +class APIModelForest extends ModelForest { /** * Request url to fill the model. @@ -760,7 +761,7 @@ class APIModelList extends ModelList { /** * Fills the instance with distant data. It sends a GET HTTP request to - * {@link Models.APIModelList#url_model}. + * {@link Models.APIModelForest#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. @@ -786,25 +787,27 @@ class APIModelList extends ModelList { /** * ArticleList model. Can be accessed through API. - * @extends Models.APIModelList + * @extends Models.APIModelForest * @memberof Models */ -class ArticleList extends APIModelList { +class ArticleList extends APIModelForest { /** * Default structure for ArticleList instances * @abstract - * @default [Article, ArticleCategory] + * @default {'article': Article, + 'category': ArticleCategory} */ static get models() { - return [Article, ArticleCategory]; + return {'article': Article, + 'category': 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} + * @see {@link Models.APIModelForest.url_model|APIModelList.url_model} */ static get url_model() { return Urls['kfet.kpsul.articles_data'](); From fe6823fc7bc9f8e96afb916880af33e15c60d27b Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 15 Mar 2017 22:39:30 -0300 Subject: [PATCH 14/38] Adapt article_data return value to ModelTree standards --- kfet/views.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 4b356d43..93557157 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1349,11 +1349,14 @@ def kpsul_articles_data(request): for article in articles: articlelist.append({ - 'id': article.id, - 'name': article.name, - 'price': article.price, - 'stock': article.stock, - 'category': { + 'type': 'article', + 'content': { + 'id': article.id, + 'name': article.name, + 'price': article.price, + 'stock': article.stock, + }, + 'parent': { 'id': article.category.id, 'name': article.category.name, } From 08d1521d8160ede23e6dd702b2d69a4551d6c536 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 15 Mar 2017 22:40:06 -0300 Subject: [PATCH 15/38] Adapt ArticleManagerto new API --- kfet/static/kfet/js/kpsul.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 238a40a6..9d5515b2 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -417,12 +417,12 @@ class ArticleManager { update_data(data) { for (let article_dict of data) { - article = this.list.find(Article, {'id': article_dict['id']}); + article = this.list.find('article', article_dict['id']); // For now, article additions are disregarded if (article) { article.stock = article_dict['stock']; - this._$container.find('#data-article-'+article_dict['id']+' .stock') + this._$container.find('#article-'+article_dict['id']+' .stock') .text(article_dict['stock']); } } From 3d760794391b5565127ab315268412e750a9dc9e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 01:20:06 -0300 Subject: [PATCH 16/38] Add correct syntax to category data --- kfet/views.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/kfet/views.py b/kfet/views.py index 93557157..1c6042e4 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1357,8 +1357,11 @@ def kpsul_articles_data(request): 'stock': article.stock, }, 'parent': { - 'id': article.category.id, - 'name': article.category.name, + 'type': 'category', + 'content': { + 'id': article.category.id, + 'name': article.category.name, + }, } }) return JsonResponse(articlelist, safe=False) From 770c185bd07934334f6cb823bae6bf071d7b27c4 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 01:21:18 -0300 Subject: [PATCH 17/38] Modify sort in ModelTree --- kfet/static/kfet/js/kfet.api.js | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index a655786d..1339f284 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -165,24 +165,11 @@ class ModelObject { /** * Returns a string value for the model, to use in comparisons - * @see {@link Models.ModelObject.compare|ModelObject.compare} + * @see {@link Models.TreeNode.compare|TreeNode.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.comparevalue().localeCompare(b.comparevalue()); - } - } @@ -552,7 +539,7 @@ class Article extends ModelObject { * @see {@link Models.ModelObject.compare|ModelObject.compare} */ comparevalue() { - return a.name; + return this.name; } // Take care of 'price' type @@ -574,6 +561,13 @@ class TreeNode { this.parent = null; this.children = []; } + + static compare(a, b) { + var a_serial = a.content.comparevalue(); + var b_serial = b.content.comparevalue(); + + return a_serial.localeCompare(b_serial) + } } From 2ce96bce1be54ea057283cb5015c71114ea0302e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 01:21:50 -0300 Subject: [PATCH 18/38] Add traverse function to ModelTree --- kfet/static/kfet/js/kfet.api.js | 43 ++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 20 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 1339f284..409c61a5 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -622,7 +622,7 @@ class ModelForest { } } - if (direction >= 0) { + if (direction >= 0 && data.children) { for (let child_data of data.children) { var child = this.get_or_create(child_data, 1); child.parent = node; @@ -669,7 +669,7 @@ class ModelForest { $container.append($rendered); //TODO: better sorting control - node.children.sort(ModelObject.compare); + node.children.sort(TreeNode.compare); for (let child of node.children) { var $child = this.render_element(child, templates, options); @@ -701,40 +701,43 @@ class ModelForest { * @param {Object} [options] Options for element render method */ display($container, templates, options) { - this.roots.sort(ModelObject.compare); + this.roots.sort(TreeNode.compare); - for (let root of roots) { + for (let root of this.roots) { $container.append(this.render_element(root, templates, options)); } return $container; } + traverse(callback) { + function recurse(node) { + callback(node) ; + + for (let child of node.children) + callback(child); + } + + for (let root of this.roots) + recurse(root); + } + /** * Find instance in data matching given properties. * @param {class} model * @param {Object} props Properties to match */ find(type, id) { - - function recurse(node) { - if (node.type === type && node.data.id === id) - return node ; - - for (let child of node.children) { - if (result = recurse(node)) - return result; - } - - return null; + var result = null; + function callback(node) { + if (node.type === type && node.content.id == id) + result = node ; } - for (let root of this.roots) { - if (result = recurse(root)) - return result; - } + this.traverse(callback); + + return result ; - return null ; } } From 01295d464d1ffd8073fe475ae57ef0a1e782758e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 01:22:46 -0300 Subject: [PATCH 19/38] Adapt ArticleAutocomplete to new format --- kfet/static/kfet/js/kpsul.js | 66 ++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 9d5515b2..e3621dee 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -488,8 +488,6 @@ class ArticleAutocomplete { constructor(article_manager) { this.manager = article_manager; - this.matching = []; - this.active_categories = []; this._$container = article_manager._$container ; this._$input = $('#article_autocomplete'); @@ -523,31 +521,30 @@ class ArticleAutocomplete { update(prefix, backspace) { + this.resetMatch(); var article_list = this.manager.list ; var lower = prefix.toLowerCase() ; var that = this ; - this.matching = article_list.data['article'] - .filter(function(article) { - return article.name.toLowerCase() - .indexOf(lower) === 0 ; + + article_list.traverse(function(node) { + if (node.type === 'article' && + node.content.name.toLowerCase() + .startsWith(lower)) { + that.matching['article'].push(node.content); + if (that.matching['category'].indexOf(node.parent.content) == -1) + that.matching['category'].push(node.parent.content); + } }); - this.active_categories = article_list.data['category'] - .filter(function(category) { - return that.matching.find(function(article) { - return article.category === category ; - }); - }); - - if (this.matching.length == 1) { + if (this.matching['article'].length == 1) { if (!backspace) { - this.manager.validate(this.matching[0]) ; + this.manager.validate(this.matching['article'][0]) ; this.showAll() ; } else { this.manager.unset(); this.updateDisplay(); } - } else if (this.matching.length > 1) { + } else if (this.matching['article'].length > 1) { this.manager.unset(); this.updateDisplay() ; if (!backspace) @@ -556,26 +553,21 @@ class ArticleAutocomplete { } updateDisplay() { - var article_list = this.manager.list ; - for (let article of article_list.data['article']) { - if (this.matching.indexOf(article) > -1) { - this._$container.find('[data-article-id='+article.id+']').show(); - } else { - this._$container.find('[data-article-id='+article.id+']').hide(); - } - } + var that = this; - for (let category of article_list.data['category']) { - if (this.active_categories.indexOf(category) > -1) { - this._$container.find('[data-category-id='+category.id+']').show(); - } else { - this._$container.find('[data-category-id='+category.id+']').hide(); + this.manager.list.traverse(function(node) { + if (that.matching[node.type].indexOf(node.content) != -1) { + that._$container.find('#'+node.type+'-'+node.content.id) + .show(); + } else { + that._$container.find('#'+node.type+'-'+node.content.id) + .hide(); } - } + }); } updatePrefix() { - var lower = this.matching.map(function (article) { + var lower = this.matching['article'].map(function (article) { return article.name.toLowerCase() ; }); @@ -588,8 +580,16 @@ class ArticleAutocomplete { } showAll() { - this.matching = this.manager.list.data['article']; - this.active_categories = this.manager.list.data['category']; + var that = this; + this.resetMatch(); + this.manager.list.traverse(function(node) { + that.matching[node.type].push(node.content); + }); this.updateDisplay(); } + + resetMatch() { + this.matching = {'article' : [], + 'category': []}; + } } From f0a80561edaba1b6ce0ed2a32886fa803853a9fb Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 22:24:57 -0300 Subject: [PATCH 20/38] Add article display to Config callback --- kfet/templates/kfet/kpsul.html | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 43a55dd2..31714bdb 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -131,10 +131,6 @@
- - - -
@@ -833,10 +829,10 @@ $(document).ready(function() { function hardReset(give_tri_focus=true) { coolReset(give_tri_focus); kpsul.checkout_manager.reset(); - kpsul.article_manager.reset_data(); resetPreviousOp(); khistory.reset(); Config.reset(function() { + kpsul.article_manager.reset_data(); displayAddcost(); getHistory(); }); From 1c5ac561a3b019ae4c12d8e0f39490d42e5b4e29 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 22:26:08 -0300 Subject: [PATCH 21/38] Change article table into divs --- kfet/static/kfet/css/kpsul.css | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 3d8c63f4..371331c0 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -296,30 +296,44 @@ input[type=number]::-webkit-outer-spin-button { #articles_data { overflow:auto; max-height:500px; -} - -#articles_data table { width: 100%; } -#articles_data table tr.article { +#articles_data div.article { height:25px; font-size:14px; } -#articles_data table tr.article>td:first-child { - padding-left:10px; +#articles_data span { + height:25px; + line-height:25px; + display: inline-block; } -#articles_data table tr.category { +#articles_data span.name { + padding-left:10px; + width:78%; +} + +#articles_data span.price { + width:8%; +} + +#articles_data span.stock { + width:14%; +} + + +#articles_data div.category { height:35px; + line-height:35px; background-color:#c8102e; font-size:16px; color:#FFF; font-weight:bold; } -#articles_data table tr.category>td:first-child { +#articles_data div.category>span:first-child { padding-left:20px; } From 91f14deda1c783eb5daccdadcbf6bb90f1bc9b3f Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 22:26:30 -0300 Subject: [PATCH 22/38] last tweaks and doc --- kfet/static/kfet/js/kfet.api.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 409c61a5..8a3e0951 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -71,8 +71,10 @@ class Config { * A model subclasses {@link Models.ModelObject}.
* A model whose instances can be got from API subclasses * {@link Models.APIModelObject}.
- * A model to manage ModelObject lists - * {@link Models.ModelList}.
+ * A model to manage ModelObject forests + * {@link Models.ModelForest}.
+ * A ModelObject that can be fetched through API + * {@link Models.APIModelForest}.
* These classes should not be used directly. *

* @@ -81,7 +83,9 @@ class Config { * {@link Models.Checkout} (partial). *
* Models without API support: - * {@link Models.Statement}. + * {@link Models.Statement}, + * {@link Models.ArticleCategory}, + * {@link Models.Article}. * * @namespace Models */ @@ -804,7 +808,7 @@ class ArticleList extends APIModelForest { * Default url to get ArticlList data * @abstract * @default django-js-reverse('kfet.kpsul.articles_data') - * @see {@link Models.APIModelForest.url_model|APIModelList.url_model} + * @see {@link Models.APIModelForest.url_model|APIModelForest.url_model} */ static get url_model() { return Urls['kfet.kpsul.articles_data'](); From 9ab2a11432bfc026f32c03d7639af8175f88f461 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Thu, 16 Mar 2017 22:26:59 -0300 Subject: [PATCH 23/38] Finish adapting ArticleManager and Autocomplete --- kfet/static/kfet/js/kpsul.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index e3621dee..b2b4c5fa 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -373,11 +373,11 @@ class ArticleManager { constructor(env) { this._env = env; // Global K-Psul Manager - this._$container = $('#articles_data tbody'); + this._$container = $('#articles_data'); this._$input = $('#article_autocomplete'); this._$nb = $('#article_number'); - this.templates = {'category': '', - 'article' : ''} + this.templates = {'category': '
', + 'article' : '
'} this.selected = new Article() ; this.list = new ArticleList() ; @@ -410,7 +410,7 @@ class ArticleManager { } reset_data() { - this._$container.find('tr').remove(); + this._$container.html(''); this.list.clear(); this.list.fromAPI({}, this.display_list.bind(this), $.noop) ; } @@ -450,10 +450,11 @@ class ArticleManager { }); this._$container.on('click', '.article', function() { - var id = $(this).attr('data-article-id') ; - var article = that.list.find(Article, { 'id': intCheck(id) }); + var id = $(this).parent().attr('id').split('-')[1]; + console.log(id); + var article = that.list.find('article', id); if (article) - that.validate(article); + that.validate(article.content); }); this._$nb.on('keydown', function(e) { From a7de396aa36ee1cdf7212b485dde622547e49f56 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 17 Mar 2017 12:33:43 -0300 Subject: [PATCH 24/38] Better comparison control --- kfet/static/kfet/js/kfet.api.js | 52 +++++++++++++++++++++------------ kfet/static/kfet/js/kpsul.js | 1 - kfet/views.py | 1 + 3 files changed, 35 insertions(+), 19 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 8a3e0951..a80b7b9c 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -498,8 +498,8 @@ class ArticleCategory extends ModelObject { * Comparison function between ArticleCategory model instances. * @see {@link Models.ModelObject.compare|ModelObject.compare} */ - comparevalue() { - return this.name ; + static compare(a, b) { + return a.name.localeCompare(b.name) ; } } @@ -542,8 +542,8 @@ class Article extends ModelObject { * Comparison function between Article model instances. * @see {@link Models.ModelObject.compare|ModelObject.compare} */ - comparevalue() { - return this.name; + static compare(a, b) { + return a.name.localeCompare(b.name); } // Take care of 'price' type @@ -565,13 +565,6 @@ class TreeNode { this.parent = null; this.children = []; } - - static compare(a, b) { - var a_serial = a.content.comparevalue(); - var b_serial = b.content.comparevalue(); - - return a_serial.localeCompare(b_serial) - } } @@ -588,6 +581,18 @@ class ModelForest { */ 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); + } + /** * Creates empty instance and populates it with data if given @@ -616,6 +621,9 @@ class ModelForest { var content = new this.constructor.models[data.type](data.content); var node = new TreeNode(data.type, content); + if (data.child_sort) + node.child_sort = data.child_sort + if (direction <= 0) { if (data.parent) { var parent = this.get_or_create(data.parent, -1); @@ -672,8 +680,8 @@ class ModelForest { var $rendered = node.content.display($(template), options); $container.append($rendered); - //TODO: better sorting control - node.children.sort(TreeNode.compare); + //dirty + node.children.sort(this.constructor.compare.bind(null, this.constructor.models[node.child_sort])); for (let child of node.children) { var $child = this.render_element(child, templates, options); @@ -705,8 +713,7 @@ class ModelForest { * @param {Object} [options] Options for element render method */ display($container, templates, options) { - this.roots.sort(TreeNode.compare); - + this.roots.sort(this.constructor.compare.bind(null, this.root_sort)); for (let root of this.roots) { $container.append(this.render_element(root, templates, options)); } @@ -727,9 +734,9 @@ class ModelForest { } /** - * Find instance in data matching given properties. - * @param {class} model - * @param {Object} props Properties to match + * Find instance in tree with given type and id + * @param {string} type + * @param {number} id */ find(type, id) { var result = null; @@ -813,6 +820,15 @@ 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; + } } diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index b2b4c5fa..1a6ca4b2 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -451,7 +451,6 @@ class ArticleManager { this._$container.on('click', '.article', function() { var id = $(this).parent().attr('id').split('-')[1]; - console.log(id); var article = that.list.find('article', id); if (article) that.validate(article.content); diff --git a/kfet/views.py b/kfet/views.py index 1c6042e4..1fd9322c 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1362,6 +1362,7 @@ def kpsul_articles_data(request): 'id': article.category.id, 'name': article.category.name, }, + 'child_sort': 'article', } }) return JsonResponse(articlelist, safe=False) From 565a054323c9443c8c70c6de0f294612a7d06691 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Fri, 17 Mar 2017 17:30:22 -0300 Subject: [PATCH 25/38] Add support for low stock css --- kfet/static/kfet/css/kpsul.css | 4 ++++ kfet/static/kfet/js/kfet.api.js | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/kfet/static/kfet/css/kpsul.css b/kfet/static/kfet/css/kpsul.css index 371331c0..20169e55 100644 --- a/kfet/static/kfet/css/kpsul.css +++ b/kfet/static/kfet/css/kpsul.css @@ -304,6 +304,10 @@ input[type=number]::-webkit-outer-spin-button { font-size:14px; } +#articles_data .article[data_stock="low"] { + background:rgba(236,100,0,0.3); +} + #articles_data span { height:25px; line-height:25px; diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index a80b7b9c..679f0e4a 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -1100,6 +1100,10 @@ class ArticleFormatter extends Formatter { return Article.props; } + static get attrs() { + return ['data_stock']; + } + static prop_price(s) { return amountToUKF(s.price, true); } @@ -1112,7 +1116,7 @@ class ArticleFormatter extends Formatter { } static attr_data_stock(a) { - if (a.stock >= 5) { return this._data_stock.ok; } + if (a.stock > 5) { return this._data_stock.ok; } else if (a.stock >= -5) { return this._data_stock.low; } else /* a.stock < -5 */ { return this._data_stock.neg; } } From fc3e86aea65d0cbbc4fadfeed85cc5b901638dba Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Sat, 18 Mar 2017 22:06:30 -0300 Subject: [PATCH 26/38] Add websocket support to ArticleManager --- kfet/static/kfet/js/kpsul.js | 5 +++-- kfet/templates/kfet/kpsul.html | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 1a6ca4b2..fd7b1a1f 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -415,9 +415,10 @@ class ArticleManager { this.list.fromAPI({}, this.display_list.bind(this), $.noop) ; } + //TODO: filter articles before ? update_data(data) { - for (let article_dict of data) { - article = this.list.find('article', article_dict['id']); + for (let article_dict of data.articles) { + var article = this.list.find('article', article_dict['id']); // For now, article additions are disregarded if (article) { diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 31714bdb..8fd903df 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -799,11 +799,9 @@ $(document).ready(function() { displayCheckoutData(); } } - for (var i=0; i Date: Mon, 20 Mar 2017 00:26:11 -0300 Subject: [PATCH 27/38] Change node.type to node.modelname for clarity --- kfet/static/kfet/js/kfet.api.js | 20 ++++++++++---------- kfet/static/kfet/js/kpsul.js | 10 +++++----- kfet/views.py | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 679f0e4a..d2fca5d7 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -560,7 +560,7 @@ class Article extends ModelObject { class TreeNode { constructor(type, content) { - this.type = type; + this.modelname = type; this.content = content; this.parent = null; this.children = []; @@ -611,15 +611,15 @@ class ModelForest { * @param {number} direction */ get_or_create(data, direction) { - var model = this.constructor.models[data.type]; + var model = this.constructor.models[data.modelname]; - var existing = this.find(data.type, data.content.id); + var existing = this.find(data.modelname, data.content.id); if (existing) { return existing; } - var content = new this.constructor.models[data.type](data.content); - var node = new TreeNode(data.type, content); + 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 @@ -671,11 +671,11 @@ class ModelForest { * @param {Object} [options] Options for element render method */ render_element(node, templates, options) { - var template = templates[node.type]; + var template = templates[node.modelname]; var options = options || {} ; var $container = $('
'); - $container.attr('id', node.type+'-'+node.content.id); + $container.attr('id', node.modelname+'-'+node.content.id); var $rendered = node.content.display($(template), options); $container.append($rendered); @@ -695,13 +695,13 @@ class ModelForest { var existing = node.parent ; var first_missing = node; - while (existing && !($container.find('#'+existing.type+'-'+existing.id))) { + while (existing && !($container.find('#'+existing.modelname+'-'+existing.id))) { first_missing = existing ; existing = existing.parent; } var $to_insert = render_element(first_missing, templates, options); - var $insert_in = existing ? $container.find('#'+existing.type+'-'+existing.id) + var $insert_in = existing ? $container.find('#'+existing.modelname+'-'+existing.id) : $container ; $insert_in.prepend($to_insert); } @@ -741,7 +741,7 @@ class ModelForest { find(type, id) { var result = null; function callback(node) { - if (node.type === type && node.content.id == id) + if (node.modelname === type && node.content.id == id) result = node ; } diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index fd7b1a1f..49c61468 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -528,7 +528,7 @@ class ArticleAutocomplete { var that = this ; article_list.traverse(function(node) { - if (node.type === 'article' && + if (node.modelname === 'article' && node.content.name.toLowerCase() .startsWith(lower)) { that.matching['article'].push(node.content); @@ -557,11 +557,11 @@ class ArticleAutocomplete { var that = this; this.manager.list.traverse(function(node) { - if (that.matching[node.type].indexOf(node.content) != -1) { - that._$container.find('#'+node.type+'-'+node.content.id) + if (that.matching[node.modelname].indexOf(node.content) != -1) { + that._$container.find('#'+node.modelname+'-'+node.content.id) .show(); } else { - that._$container.find('#'+node.type+'-'+node.content.id) + that._$container.find('#'+node.modelname+'-'+node.content.id) .hide(); } }); @@ -584,7 +584,7 @@ class ArticleAutocomplete { var that = this; this.resetMatch(); this.manager.list.traverse(function(node) { - that.matching[node.type].push(node.content); + that.matching[node.modelname].push(node.content); }); this.updateDisplay(); } diff --git a/kfet/views.py b/kfet/views.py index 1fd9322c..befe92d4 100644 --- a/kfet/views.py +++ b/kfet/views.py @@ -1349,7 +1349,7 @@ def kpsul_articles_data(request): for article in articles: articlelist.append({ - 'type': 'article', + 'modelname': 'article', 'content': { 'id': article.id, 'name': article.name, @@ -1357,7 +1357,7 @@ def kpsul_articles_data(request): 'stock': article.stock, }, 'parent': { - 'type': 'category', + 'modelname': 'category', 'content': { 'id': article.category.id, 'name': article.category.name, From 3ce4dc5c859407195bf0468239be0fa2fb75b793 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Mon, 3 Apr 2017 20:14:45 -0300 Subject: [PATCH 28/38] Add article stock management --- kfet/static/kfet/js/kpsul.js | 3 +++ kfet/templates/kfet/kpsul.html | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 67af4e57..f8270855 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -376,6 +376,7 @@ class ArticleManager { this._$container = $('#articles_data'); this._$input = $('#article_autocomplete'); this._$nb = $('#article_number'); + this._$stock = $('#article_stock'); this.templates = {'category': '
', 'article' : '
'} @@ -398,6 +399,7 @@ class ArticleManager { this.selected.from(article) ; this._$input.val(article.name); this._$nb.val('1'); + this._$stock.text('/'+article.stock); this._$nb.focus().select(); } @@ -431,6 +433,7 @@ class ArticleManager { reset() { this.unset() ; + this._$stock.text(''); this._$nb.val(''); this._$input.val(''); this.autocomplete.showAll() ; diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 3feba529..493a9e97 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -128,7 +128,6 @@ -
From 05156f37c659239a123e36091bee3a8a273f68ed Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 19:34:22 -0300 Subject: [PATCH 29/38] Update addExistingPurchase --- kfet/static/kfet/js/kpsul.js | 13 ++++++++----- kfet/templates/kfet/kpsul.html | 15 ++++++--------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index f8270855..374068f3 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -417,16 +417,19 @@ class ArticleManager { this.list.fromAPI({}, this.display_list.bind(this), $.noop) ; } - //TODO: filter articles before ? + get_article(id) { + return this.list.find('article', id).content; + } + update_data(data) { for (let article_dict of data.articles) { - var article = this.list.find('article', article_dict['id']); + var article = this.get_article(article_dict.id); // For now, article additions are disregarded if (article) { - article.stock = article_dict['stock']; - this._$container.find('#article-'+article_dict['id']+' .stock') - .text(article_dict['stock']); + article.stock = article_dict.stock; + this._$container.find('#article-'+article.id+' .stock') + .text(article.stock); } } } diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 493a9e97..dd7d4cdb 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -464,15 +464,12 @@ $(document).ready(function() { function addExistingPurchase(opeindex, nb) { var type = formset_container.find("#id_form-"+opeindex+"-type").val(); var id = formset_container.find("#id_form-"+opeindex+"-article").val(); + var article = kpsul.article_manager.get_article(parseInt(id)); var nb_before = formset_container.find("#id_form-"+opeindex+"-article_nb").val(); var nb_after = parseInt(nb_before) + parseInt(nb); - var amountEuro_after = amountEuroPurchase(id, nb_after); + var amountEuro_after = amountEuroPurchase(article, nb_after); var amountUKF_after = amountToUKF(amountEuro_after, kpsul.account_manager.account.is_cof, false); - var i = 0; - while (i 0) { var article_html = basket_container.find('[data-opeindex='+opeindex+']'); article_html.find('.amount').text(amountUKF_after).end() - .find('.number').text('('+nb_after+'/'+article_data[4]+')').end() ; + .find('.number').text('('+nb_after+'/'+article.stock+')').end() ; } else { article_html = $(item_basket_default_html); article_html .attr('data-opeindex', opeindex) - .find('.number').text('('+nb_after+'/'+article_data[4]+')').end() - .find('.name').text(article_data[0]).end() + .find('.number').text('('+nb_after+'/'+article.stock+')').end() + .find('.name').text(article.name).end() .find('.amount').text(amountUKF_after); basket_container.prepend(article_basket_html); } - if (is_low_stock(id, nb_after)) + if (is_low_stock(article, nb_after)) article_html.find('.lowstock') .show(); else From e5791efe4df211fdac77f43c43c3ca2a5a824fa1 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 19:41:15 -0300 Subject: [PATCH 30/38] Remove last traces of old articles --- kfet/static/kfet/js/kpsul.js | 10 +++++++--- kfet/templates/kfet/kpsul.html | 27 ++++++--------------------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 374068f3..12a80d94 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -85,7 +85,7 @@ class AccountManager { $('#id_on_acc').val(this.account.id); this.display(); - kpsul._env.articleSelect.focus(); + kpsul.article_manager.focus(); kpsul._env.updateBasketAmount(); kpsul._env.updateBasketRel(); } @@ -268,7 +268,7 @@ class CheckoutManager { if (kpsul.account_manager.is_empty()) { kpsul.account_manager.focus(); } else { - kpsul._env.articleSelect.focus().select(); + kpsul.article_manager.focus(); } } @@ -482,7 +482,11 @@ class ArticleManager { } focus() { - this._$input.focus(); + if this.is_empty() + this._$input.focus(); + else + this._$nb.focus(); + return this; } diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index dd7d4cdb..283c4692 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -191,7 +191,7 @@ $(document).ready(function() { commentDialog.open({ callback: confirm_callback, - next_focus: articleSelect + next_focus: kpsul.article_manager; }); } @@ -237,7 +237,7 @@ $(document).ready(function() { else displayErrors(getErrorsHtml(response)); }, - next_focus: articleSelect, + next_focus: kpsul.article_manager, }); } @@ -273,15 +273,6 @@ $(document).ready(function() { cancelOperations(); }); - // ----- - // Articles data - // ----- - - var articleSelect = $('#article_autocomplete'); - var articleId = $('#article_id'); - var articleNb = $('#article_number'); - var articlesList = []; - // ----- // Basket // ----- @@ -527,11 +518,9 @@ $(document).ready(function() { addDeposit(amount); } - var next_focus = articleSelect.val() ? articleNb : articleSelect ; - depositDialog.open({ callback: callback, - next_focus: next_focus, + next_focus: kpsul.article_manager, }); } @@ -547,11 +536,9 @@ $(document).ready(function() { addEdit(amount); } - var next_focus = articleSelect.val() ? articleNb : articleSelect ; - editDialog.open({ callback: callback, - next_focus: next_focus, + next_focus: kpsul.article_manager, }); } @@ -567,11 +554,9 @@ $(document).ready(function() { addWithdraw(amount); } - var next_focus = articleSelect.val() ? articleNb : articleSelect ; - withdrawDialog.open({ callback: callback, - next_focus: next_focus, + next_focus: kpsul.article_manager, }); } @@ -862,7 +847,7 @@ $(document).ready(function() { } else { // F2 - Basket reset resetBasket(); - articleSelect.focus(); + kpsul.article_manager.focus(); } return false; case 114: From cb28b928c42f68f146ce484e1e21aa5fd1b3ab11 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 19:42:30 -0300 Subject: [PATCH 31/38] Remove articleSelect from _env --- kfet/templates/kfet/kpsul.html | 1 - 1 file changed, 1 deletion(-) diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 283c4692..2db6a54e 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -879,7 +879,6 @@ $(document).ready(function() { // ----- var env = { - articleSelect: articleSelect, addPurchase: addPurchase, updateBasketAmount: updateBasketAmount, updateBasketRel: updateBasketRel, From 021937a38e86791d11e5e5f83a932c5d8eca1bad Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 19:52:12 -0300 Subject: [PATCH 32/38] Small bugfixes --- kfet/static/kfet/js/kpsul.js | 2 +- kfet/templates/kfet/kpsul.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 12a80d94..30197b9f 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -482,7 +482,7 @@ class ArticleManager { } focus() { - if this.is_empty() + if (this.is_empty()) this._$input.focus(); else this._$nb.focus(); diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index 2db6a54e..c1243d4a 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -191,7 +191,7 @@ $(document).ready(function() { commentDialog.open({ callback: confirm_callback, - next_focus: kpsul.article_manager; + next_focus: kpsul.article_manager, }); } From 9c559d9ec33d630627486e2d3a7a8c32df81509e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 19:54:03 -0300 Subject: [PATCH 33/38] Add articles reset to kpsul.reset --- kfet/static/kfet/js/kpsul.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 30197b9f..972f93c3 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -11,9 +11,11 @@ class KPsulManager { soft = soft || false; this.account_manager.reset(); + this.article_manager.reset(); if (!soft) { this.checkout_manager.reset(); + this.article_manager.reset_data(); } } From 3b9affb3f32e9a6e08866962be53d95f47f1081e Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Tue, 4 Apr 2017 20:18:53 -0300 Subject: [PATCH 34/38] Add focus methods --- kfet/static/kfet/js/kpsul.js | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 972f93c3..0027543e 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -19,6 +19,17 @@ class KPsulManager { } } + focus() { + if (this.checkout_manager.is_empty()) + this.checkout_manager.focus(); + else if (this.account_manager.is_empty()) + this.account_manager.focus(); + else + this.article_manager.focus(); + + return this; + } + } @@ -267,11 +278,7 @@ class CheckoutManager { (data) => this._update_on_success(data), () => this.reset_data()); - if (kpsul.account_manager.is_empty()) { - kpsul.account_manager.focus(); - } else { - kpsul.article_manager.focus(); - } + kpsul.focus(); } _update_on_success(data) { @@ -336,6 +343,11 @@ class CheckoutManager { this.display(); } + + focus() { + this.selection.focus(); + return this; + } } @@ -368,6 +380,11 @@ class CheckoutSelection { reset() { this._$input.find('option:first').prop('selected', true); } + + focus() { + this._$input.focus(); + return this; + } } class ArticleManager { From a29de134f165be6ca072f70fbcd62663c5444bcf Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 5 Apr 2017 08:58:46 -0300 Subject: [PATCH 35/38] Move focus ; move is_low_stock to method --- kfet/static/kfet/js/kfet.api.js | 4 ++++ kfet/static/kfet/js/kpsul.js | 2 +- kfet/templates/kfet/kpsul.html | 12 ++++-------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 293ff6a2..3fb3860e 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -502,6 +502,10 @@ class Article extends ModelObject { // API currently returns a string object (serialization of Decimal type within Django) get price() { return this._price; } set price(v) { this._price = floatCheck(v); } + + is_low_stock(nb) { + return (-5 <= this.stock - nb && this.stock - nb <= 5); + } } diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 0027543e..9474e46f 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -98,7 +98,7 @@ class AccountManager { $('#id_on_acc').val(this.account.id); this.display(); - kpsul.article_manager.focus(); + kpsul.focus(); kpsul._env.updateBasketAmount(); kpsul._env.updateBasketRel(); } diff --git a/kfet/templates/kfet/kpsul.html b/kfet/templates/kfet/kpsul.html index c1243d4a..38a9e323 100644 --- a/kfet/templates/kfet/kpsul.html +++ b/kfet/templates/kfet/kpsul.html @@ -191,7 +191,7 @@ $(document).ready(function() { commentDialog.open({ callback: confirm_callback, - next_focus: kpsul.article_manager, + next_focus: kpsul, }); } @@ -237,7 +237,7 @@ $(document).ready(function() { else displayErrors(getErrorsHtml(response)); }, - next_focus: kpsul.article_manager, + next_focus: kpsul, }); } @@ -312,17 +312,13 @@ $(document).ready(function() { .find('.name').text(article.name).end() .find('.amount').text(amountToUKF(amount_euro, kpsul.account_manager.account.is_cof)); basket_container.prepend(article_basket_html); - if (is_low_stock(article, nb)) + if (article.is_low_stock(nb)) article_basket_html.find('.lowstock') .show(); updateBasketRel(); } } - function is_low_stock(article, nb) { - return (-5 <= article.stock - nb && article.stock - nb <= 5); - } - function addDeposit(amount) { var deposit_basket_html = $(item_basket_default_html); var amount = parseFloat(amount).toFixed(2); @@ -481,7 +477,7 @@ $(document).ready(function() { } - if (is_low_stock(article, nb_after)) + if (article.is_low_stock(nb_after)) article_html.find('.lowstock') .show(); else From 1761c5f1bdca39de20707b9034369ad867899847 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 5 Apr 2017 09:13:00 -0300 Subject: [PATCH 36/38] Change fromAPI logic --- kfet/static/kfet/js/kfet.api.js | 18 ++++-------------- kfet/static/kfet/js/kpsul.js | 3 ++- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index ab6cc7ab..9d805fdc 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -754,24 +754,14 @@ class APIModelForest extends ModelForest { * Fills the instance with distant data. It sends a GET HTTP request to * {@link Models.APIModelForest#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; + fromAPI(api_options) { + api_options = api_options || {}; api_options['format'] = 'json'; - $.getJSON(this.constructor.url_model, api_options) - .done(function(json, textStatus, jqXHR) { - that.from(json); - on_success(json, textStatus, jqXHR); - }) - .fail(on_error); + return $.getJSON(this.constructor.url_model, api_options) + .done( (json) => this.from(json) ); } } diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index 703b15b2..e6784f7e 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -451,7 +451,8 @@ class ArticleManager { reset_data() { this._$container.html(''); this.list.clear(); - this.list.fromAPI({}, this.display_list.bind(this), $.noop) ; + this.list.fromAPI() + .done( () => this.display_list() ); } get_article(id) { From 508e7ec23fcd8bf94fd0d0dbc633e60dd0a66e3c Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 5 Apr 2017 12:00:39 -0300 Subject: [PATCH 37/38] Change traverse and find behavior --- kfet/static/kfet/js/kfet.api.js | 52 +++++++++++++++++++++++++-------- kfet/static/kfet/js/kpsul.js | 51 +++++++++++++++++--------------- 2 files changed, 68 insertions(+), 35 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 9d805fdc..730fab12 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -596,7 +596,7 @@ class ModelForest { get_or_create(data, direction) { var model = this.constructor.models[data.modelname]; - var existing = this.find(data.modelname, data.content.id); + var existing = this.find_node(data.modelname, data.content.id); if (existing) { return existing; } @@ -704,12 +704,40 @@ class ModelForest { return $container; } - traverse(callback) { + /** + * Find if node already exists in given tree + * @param {Models.TreeNode} + */ + find_node(modelname, id) { + var result = null; + function recurse(node) { - callback(node) ; + if (node.modelname === modelname && node.content.id === id) + result = node; for (let child of node.children) - callback(child); + 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. + * @param {string} modelname + * @param {function} callback + */ + traverse(modelname, callback) { + function recurse(node) { + if (node.modelname === modelname) + callback(node.content, node.parent && node.parent.content || null) ; + + for (let child of node.children) + recurse(child); } for (let root of this.roots) @@ -718,20 +746,20 @@ class ModelForest { /** * Find instance in tree with given type and id - * @param {string} type + * @param {string} modelname * @param {number} id */ - find(type, id) { + find(modelname, id) { var result = null; - function callback(node) { - if (node.modelname === type && node.content.id == id) - result = node ; + + function callback(content) { + if (content.id == id) + result = content ; } - this.traverse(callback); - - return result ; + this.traverse(modelname, callback); + return result; } } diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index e6784f7e..af2e4f5f 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -456,7 +456,7 @@ class ArticleManager { } get_article(id) { - return this.list.find('article', id).content; + return this.list.find('article', id); } update_data(data) { @@ -498,7 +498,7 @@ class ArticleManager { var id = $(this).parent().attr('id').split('-')[1]; var article = that.list.find('article', id); if (article) - that.validate(article.content); + that.validate(article); }); this._$nb.on('keydown', function(e) { @@ -575,25 +575,23 @@ class ArticleAutocomplete { var lower = prefix.toLowerCase() ; var that = this ; - article_list.traverse(function(node) { - if (node.modelname === 'article' && - node.content.name.toLowerCase() - .startsWith(lower)) { - that.matching['article'].push(node.content); - if (that.matching['category'].indexOf(node.parent.content) == -1) - that.matching['category'].push(node.parent.content); + article_list.traverse('article', function(article, category) { + if (article.name.toLowerCase().startsWith(lower)) { + that.matching.push(article); + if (that.active_categories.indexOf(category) == -1) + that.active_categories.push(category); } }); - if (this.matching['article'].length == 1) { + if (this.matching.length == 1) { if (!backspace) { - this.manager.validate(this.matching['article'][0]) ; + this.manager.validate(this.matching[0]) ; this.showAll() ; } else { this.manager.unset(); this.updateDisplay(); } - } else if (this.matching['article'].length > 1) { + } else if (this.matching.length > 1) { this.manager.unset(); this.updateDisplay() ; if (!backspace) @@ -604,19 +602,23 @@ class ArticleAutocomplete { updateDisplay() { var that = this; - this.manager.list.traverse(function(node) { - if (that.matching[node.modelname].indexOf(node.content) != -1) { - that._$container.find('#'+node.modelname+'-'+node.content.id) - .show(); + this.manager.list.traverse('article', function(article, category) { + if (that.matching.indexOf(article) != -1) { + that._$container.find('#article-'+article.id).show(); } else { - that._$container.find('#'+node.modelname+'-'+node.content.id) - .hide(); + that._$container.find('#article-'+article.id).hide(); + } + + if (that.active_categories.indexOf(category) != -1) { + that._$container.find('#category-'+category.id).show(); + } else { + that._$container.find('#category-'+category.id).hide(); } }); } updatePrefix() { - var lower = this.matching['article'].map(function (article) { + var lower = this.matching.map(function (article) { return article.name.toLowerCase() ; }); @@ -631,14 +633,17 @@ class ArticleAutocomplete { showAll() { var that = this; this.resetMatch(); - this.manager.list.traverse(function(node) { - that.matching[node.modelname].push(node.content); + this.manager.list.traverse('article', function(article) { + that.matching.push(article); + }); + this.manager.list.traverse('category', function(category) { + that.active_categories.push(category); }); this.updateDisplay(); } resetMatch() { - this.matching = {'article' : [], - 'category': []}; + this.matching = []; + this.active_categories = []; } } From 5c422e892a65432a9dc1ab6da491f514992b8cd4 Mon Sep 17 00:00:00 2001 From: Ludovic Stephan Date: Wed, 5 Apr 2017 12:31:19 -0300 Subject: [PATCH 38/38] Add children fo traverse callback --- kfet/static/kfet/js/kfet.api.js | 7 +++++-- kfet/static/kfet/js/kpsul.js | 27 ++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/kfet/static/kfet/js/kfet.api.js b/kfet/static/kfet/js/kfet.api.js index 730fab12..4f73e20b 100644 --- a/kfet/static/kfet/js/kfet.api.js +++ b/kfet/static/kfet/js/kfet.api.js @@ -733,8 +733,11 @@ class ModelForest { */ traverse(modelname, callback) { function recurse(node) { - if (node.modelname === modelname) - callback(node.content, node.parent && node.parent.content || null) ; + 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); + } for (let child of node.children) recurse(child); diff --git a/kfet/static/kfet/js/kpsul.js b/kfet/static/kfet/js/kpsul.js index af2e4f5f..e1bb2b55 100644 --- a/kfet/static/kfet/js/kpsul.js +++ b/kfet/static/kfet/js/kpsul.js @@ -575,12 +575,9 @@ class ArticleAutocomplete { var lower = prefix.toLowerCase() ; var that = this ; - article_list.traverse('article', function(article, category) { - if (article.name.toLowerCase().startsWith(lower)) { + article_list.traverse('article', function(article) { + if (article.name.toLowerCase().startsWith(lower)) that.matching.push(article); - if (that.active_categories.indexOf(category) == -1) - that.active_categories.push(category); - } }); if (this.matching.length == 1) { @@ -602,14 +599,18 @@ class ArticleAutocomplete { updateDisplay() { var that = this; - this.manager.list.traverse('article', function(article, category) { - if (that.matching.indexOf(article) != -1) { - that._$container.find('#article-'+article.id).show(); - } else { - that._$container.find('#article-'+article.id).hide(); + this.manager.list.traverse('category', function(category, articles) { + var is_active = false; + for (let article of articles) { + if (that.matching.indexOf(article) != -1) { + is_active = true; + that._$container.find('#article-'+article.id).show(); + } else { + that._$container.find('#article-'+article.id).hide(); + } } - if (that.active_categories.indexOf(category) != -1) { + if (is_active) { that._$container.find('#category-'+category.id).show(); } else { that._$container.find('#category-'+category.id).hide(); @@ -636,14 +637,10 @@ class ArticleAutocomplete { this.manager.list.traverse('article', function(article) { that.matching.push(article); }); - this.manager.list.traverse('category', function(category) { - that.active_categories.push(category); - }); this.updateDisplay(); } resetMatch() { this.matching = []; - this.active_categories = []; } }