From b8a9e11825d5f39417bcb60be2fe2e5e3c99a6c4 Mon Sep 17 00:00:00 2001
From: Henning Leutz <leutz@pcsg.de>
Date: Wed, 7 Sep 2022 09:29:31 +0200
Subject: [PATCH] refactor: article list -> delete, replace buttons, better UX

---
 bin/backend/controls/articles/Article.css    |  29 +++++
 bin/backend/controls/articles/Article.html   |  10 ++
 bin/backend/controls/articles/Article.js     | 125 +++++++++----------
 bin/backend/controls/articles/ArticleList.js |  33 ++---
 4 files changed, 114 insertions(+), 83 deletions(-)

diff --git a/bin/backend/controls/articles/Article.css b/bin/backend/controls/articles/Article.css
index 2f516ac..1a64784 100644
--- a/bin/backend/controls/articles/Article.css
+++ b/bin/backend/controls/articles/Article.css
@@ -52,9 +52,14 @@
 }
 
 .quiqqer-erp-backend-erpArticle-pos {
+    cursor: pointer;
     width: 50px;
 }
 
+.quiqqer-erp-backend-erpArticle-pos:hover {
+    background: #eaeaea;
+}
+
 .quiqqer-erp-backend-erpArticle-text {
     width: calc(100% - 900px);
 }
@@ -204,4 +209,28 @@
 
 .quiqqer-erp-backend-erpArticle-customFields-entry:hover {
     background-color: #dedede;
+}
+
+/*+
+ * Custom fields
+ */
+.quiqqer-erp-backend-erpArticle-articleEdit {
+    background: #DEDEDE;
+    display: none;
+    width: 100%;
+}
+
+.quiqqer-erp-backend-erpArticle-articleEdit button {
+    background: transparent;
+    border: none;
+    cursor: pointer;
+    line-height: 20px;
+}
+
+.quiqqer-erp-backend-erpArticle-select .quiqqer-erp-backend-erpArticle-articleEdit {
+    display: inline-block;
+}
+
+.quiqqer-erp-backend-erpArticle-articleEdit button:hover {
+    background: #eaeaea;
 }
\ No newline at end of file
diff --git a/bin/backend/controls/articles/Article.html b/bin/backend/controls/articles/Article.html
index c545196..72db2e6 100644
--- a/bin/backend/controls/articles/Article.html
+++ b/bin/backend/controls/articles/Article.html
@@ -22,4 +22,14 @@
         <b>{{title}}:</b><br/>{{{valueText}}}
     </div>
     {{/customFields}}
+</div>
+<div class="quiqqer-erp-backend-erpArticle-articleEdit">
+    <button name="replace">
+        <span class="fa fa-retweet"></span>
+        <span>{{buttonReplace}}</span>
+    </button>
+    <button name="delete">
+        <span class="fa fa-trash"></span>
+        <span>{{buttonDelete}}</span>
+    </button>
 </div>
\ No newline at end of file
diff --git a/bin/backend/controls/articles/Article.js b/bin/backend/controls/articles/Article.js
index a94abd2..29e3686 100644
--- a/bin/backend/controls/articles/Article.js
+++ b/bin/backend/controls/articles/Article.js
@@ -153,23 +153,23 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @returns {HTMLDivElement}
          */
         create: function () {
-            var self = this;
+            const self = this;
 
             this.$Elm = this.parent();
             this.$Elm.addClass('quiqqer-erp-backend-erpArticle');
 
-            var showSelectCheckbox = this.getAttribute('showSelectCheckbox');
+            const showSelectCheckbox = this.getAttribute('showSelectCheckbox');
 
-            var nl2br = (str, is_xhtml) => {
-                var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br ' + '/>' : '<br>'; // Adjust comment to avoid issue on phpjs.org display
+            const nl2br = (str, is_xhtml) => {
+                const breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br ' + '/>' : '<br>'; // Adjust comment to avoid issue on phpjs.org display
                 return str.replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/gm, '$1' + breakTag + '$2');
             };
 
-            var CustomFields = this.getAttribute('customFields');
-            var CustomFieldValues = {};
+            const CustomFields = this.getAttribute('customFields');
+            const CustomFieldValues = {};
 
-            for (var [fieldId, FieldData] of Object.entries(CustomFields)) {
-                var FieldDataClone = Object.clone(FieldData);
+            for (let [fieldId, FieldData] of Object.entries(CustomFields)) {
+                let FieldDataClone = Object.clone(FieldData);
 
                 CustomFieldValues[fieldId] = {
                     title    : FieldDataClone.title,
@@ -180,7 +180,9 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
             this.$Elm.set({
                 html      : Mustache.render(template, {
                     showSelectCheckbox: showSelectCheckbox,
-                    customFields      : Object.values(CustomFieldValues)
+                    customFields      : Object.values(CustomFieldValues),
+                    buttonReplace     : QUILocale.get(lg, 'articleList.article.button.replace'),
+                    buttonDelete      : QUILocale.get(lg, 'articleList.article.button.delete'),
                 }),
                 'tabindex': -1,
                 styles    : {
@@ -194,7 +196,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 this.$onCustomFieldClick
             );
 
-            var EditFields = this.getAttribute('editFields');
+            const EditFields = this.getAttribute('editFields');
 
             if (showSelectCheckbox) {
                 this.$SelectCheckbox = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-selectbox > input');
@@ -221,7 +223,10 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
             this.$VAT = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-vat');
             this.$Discount = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-discount');
             this.$Total = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-total');
-            this.$Buttons = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-buttons');
+            //this.$Buttons = this.$Elm.getElement('.quiqqer-erp-backend-erpArticle-buttons');
+
+            this.$ButtonReplace = this.$Elm.getElement('button[name="replace"]');
+            this.$ButtonDelete = this.$Elm.getElement('button[name="delete"]');
 
             if ('articleNo' in EditFields && EditFields.articleNo) {
                 this.$ArticleNo.addEvent('click', this.$onEditArticleNo);
@@ -388,29 +393,15 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
 
             // edit buttons
             if (this.getAttribute('replaceable')) {
-                new QUIButton({
-                    title : QUILocale.get(lg, 'erp.articleList.article.button.replace'),
-                    icon  : 'fa fa-retweet',
-                    styles: {
-                        'float': 'none'
-                    },
-                    events: {
-                        onClick: this.$onReplaceClick
-                    }
-                }).inject(this.$Buttons);
+                this.$ButtonReplace.addEvent('click', this.$onReplaceClick);
+            } else {
+                this.$ButtonReplace.setStyle('display', 'none');
             }
 
             if (this.getAttribute('deletable')) {
-                new QUIButton({
-                    title : QUILocale.get(lg, 'erp.articleList.article.button.delete'),
-                    icon  : 'fa fa-trash',
-                    styles: {
-                        'float': 'none'
-                    },
-                    events: {
-                        onClick: this.openDeleteDialog
-                    }
-                }).inject(this.$Buttons);
+                this.$ButtonDelete.addEvent('click', this.openDeleteDialog);
+            } else {
+                this.$ButtonDelete.setStyle('display', 'none');
             }
 
             this.$created = true;
@@ -548,12 +539,13 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @return {Promise}
          */
         $calc: function () {
-            var Calc;
+            let Calc;
+
+            const self = this,
+                  attr = self.getAttributes(),
+                  pos  = parseInt(attr.position);
 
-            var self       = this,
-                attr       = self.getAttributes(),
-                pos        = parseInt(attr.position),
-                calcByList = false;
+            let calcByList = false;
 
             if (this.getAttribute('calcByList') && this.getAttribute('List')) {
                 Calc = this.getAttribute('List').$executeCalculation();
@@ -649,6 +641,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                     });
 
                     resolve(this.$Formatter);
+                }).catch(function (err) {
+                    console.error(err);
                 });
             });
         },
@@ -834,8 +828,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @param {String|Number} discount - 100 = 100€, 100€ = 100€ or 10% =  calculation
          */
         setDiscount: function (discount) {
-            var self  = this,
-                value = '',
+            const self = this;
+            let value = '',
                 type  = '';
 
             if (discount === '' || !discount) {
@@ -846,7 +840,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 type = '%';
             }
 
-            var Prom;
+            let Prom;
 
             if (discount && type === '%') {
                 Prom = Promise.resolve(discount);
@@ -982,7 +976,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 return;
             }
 
-            var self = this;
+            const self = this;
 
             new QUIConfirm({
                 title    : QUILocale.get(lg, 'dialog.edit.description.title', {
@@ -996,7 +990,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                     onOpen: function (Win) {
                         Win.Loader.show();
 
-                        var Content = Win.getContent();
+                        const Content = Win.getContent();
 
                         Content.addClass(
                             'quiqqer-erp-dialog-edit-article-description'
@@ -1008,8 +1002,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                                   '<div class="quiqqer-erp-dialog-edit-article-description-editor"></div>'
                         });
 
-                        var Title = Content.getElement('[name="title"]');
-                        var EditorContainer = Content.getElement(
+                        const Title = Content.getElement('[name="title"]');
+                        const EditorContainer = Content.getElement(
                             '.quiqqer-erp-dialog-edit-article-description-editor'
                         );
 
@@ -1094,7 +1088,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                     },
 
                     onSubmit: function (Win) {
-                        var description = self.$Editor.getContent();
+                        const description = self.$Editor.getContent();
 
                         Win.Loader.show();
 
@@ -1102,7 +1096,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                             self.setDescription(sanitizedDescription);
                             self.setTitle(Win.getContent().getElement('[name="title"]').value);
 
-                            var NextEditCell = self.$Text.getNext('.cell-editable');
+                            const NextEditCell = self.$Text.getNext('.cell-editable');
 
                             if (NextEditCell) {
                                 QUIElements.simulateEvent(self.$Text.getNext('.cell-editable'), 'click');
@@ -1149,7 +1143,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * Edit quantity unit
          */
         $onEditQuantityUnit: function () {
-            var self = this;
+            const self = this;
 
             require([
                 'package/quiqqer/erp/bin/backend/controls/articles/product/QuantityUnitWindow'
@@ -1176,7 +1170,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * event : on quantity edit
          */
         $onEditUnitPriceQuantity: function () {
-            var self = this;
+            const self = this;
 
             this.$createEditField(
                 this.$UnitPrice,
@@ -1191,7 +1185,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * event : on brutto price edit
          */
         $onEditBruttoPrice: function () {
-            var self = this;
+            const self = this;
 
             this.$createEditField(
                 this.$UnitPriceBrutto,
@@ -1208,7 +1202,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * event: on edit VAT
          */
         $onEditVat: function () {
-            var self = this;
+            const self = this;
 
             require([
                 'package/quiqqer/tax/bin/controls/taxList/AvailableTaxListWindow'
@@ -1232,7 +1226,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * event: on edit discount
          */
         $onEditDiscount: function () {
-            var discount = this.getAttribute('discount');
+            let discount = this.getAttribute('discount');
 
             if (discount === '-' || discount === false || !discount) {
                 discount = '';
@@ -1252,8 +1246,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * event: on brutto edit discount
          */
         $onEditBruttoDiscount: function () {
-            var self     = this,
-                discount = this.$DiscountBrutto.get('data-value');
+            const self = this;
+            let discount = this.$DiscountBrutto.get('data-value');
 
             if (discount === '-' || discount === false || !discount) {
                 discount = '';
@@ -1261,10 +1255,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 discount = parseFloat(discount);
             }
 
-            this.$createEditField(
-                this.$DiscountBrutto,
-                discount
-            ).then(function (value) {
+            this.$createEditField(this.$DiscountBrutto, discount).then(function (value) {
                 if (value.match('%')) {
                     return self.setDiscount(value);
                 }
@@ -1296,12 +1287,12 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @returns {Promise}
          */
         $createEditField: function (Container, value, type, inputAttributes) {
-            var self = this;
+            const self = this;
 
             type = type || 'text';
 
             return new Promise(function (resolve) {
-                var Edit = new Element('input', {
+                const Edit = new Element('input', {
                     type  : type,
                     value : value,
                     styles: {
@@ -1332,7 +1323,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 Edit.focus();
                 Edit.select();
 
-                var onFinish = function () {
+                const onFinish = function () {
                     Edit.destroy();
                     resolve(Edit.value);
                 };
@@ -1369,7 +1360,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @param event
          */
         $editNext: function (event) {
-            var Cell = event.target;
+            let Cell = event.target;
 
             if (!Cell.hasClass('cell')) {
                 Cell = Cell.getParent('.cell');
@@ -1379,7 +1370,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                 return;
             }
 
-            var Next, Article, NextArticle, PreviousArticle;
+            let Next, Article, NextArticle, PreviousArticle;
 
             if (event.shift) {
                 Next = Cell.getPrevious('.cell-editable');
@@ -1447,12 +1438,12 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @return {Promise}
          */
         $loadDefaultQuantityUnit: function () {
-            var self = this;
+            const self = this;
 
             return new Promise(function (resolve) {
                 QUIAjax.get('package_quiqqer_erp_ajax_products_getQuantityUnitList', function (unitList) {
-                    var i, title, entry;
-                    var current = QUILocale.getCurrent();
+                    let i, title, entry;
+                    let current = QUILocale.getCurrent();
 
                     for (i in unitList) {
                         if (!unitList.hasOwnProperty(i)) {
@@ -1472,7 +1463,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
                         title = entry.title[Object.keys(entry.title)[0]];
                     }
 
-                    var result = {
+                    const result = {
                         id   : i,
                         title: title
                     };
@@ -1493,7 +1484,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @return {Promise}
          */
         getNettoPrice: function (value, formatted) {
-            var self = this;
+            const self = this;
 
             return new Promise(function (resolve) {
                 QUIAjax.get('package_quiqqer_erp_ajax_calcNettoPrice', resolve, {
@@ -1513,7 +1504,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/Article', [
          * @return {Promise}
          */
         getBruttoPrice: function (value, formatted) {
-            var self = this;
+            const self = this;
 
             return new Promise(function (resolve) {
                 QUIAjax.get('package_quiqqer_erp_ajax_calcBruttoPrice', resolve, {
diff --git a/bin/backend/controls/articles/ArticleList.js b/bin/backend/controls/articles/ArticleList.js
index cd35bfd..fe840c5 100644
--- a/bin/backend/controls/articles/ArticleList.js
+++ b/bin/backend/controls/articles/ArticleList.js
@@ -30,7 +30,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
              QUIAjax, QUILocale, AddProductWindow, Article, Sortables, template, templateSortablePlaceholder) {
     "use strict";
 
-    var lg = 'quiqqer/erp';
+    const lg = 'quiqqer/erp';
 
     return new Class({
 
@@ -98,6 +98,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
 
             this.$Elm = this.parent();
             this.$Elm.addClass('quiqqer-erp-backend-erpItems');
+            this.$Elm.set('data-qui', 'package/quiqqer/erp/bin/backend/controls/articles/ArticleList');
 
             this.$Elm.set({
                 html: Mustache.render(template, {
@@ -118,7 +119,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
             }
 
             this.$Container = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-items');
-            var SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc');
+            const SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc');
 
             this.$Switch = new QUISwitch({
                 switchTextOn     : 'netto',
@@ -161,8 +162,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
          * @returns {Object}
          */
         serialize: function () {
-            var articles = this.$getArticles().map(function (Article) {
-                var attr = Article.getAttributes();
+            const articles = this.$getArticles().map(function (Article) {
+                const attr = Article.getAttributes();
                 attr.control = typeOf(Article);
 
                 return attr;
@@ -193,8 +194,8 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
          * @return {Promise}
          */
         unserialize: function (list) {
-            var self = this,
-                data = {};
+            const self = this;
+            let data = {};
 
             if (typeOf(list) === 'string') {
                 try {
@@ -215,7 +216,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
 
             this.$articles = [];
 
-            var controls = data.articles.map(function (Article) {
+            const controls = data.articles.map(function (Article) {
                 if (typeof Article.control !== 'undefined' && Article.control !== '') {
                     return Article.control;
                 }
@@ -224,7 +225,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
             }).unique();
 
             require(controls, function () {
-                var i, len, article, index;
+                let i, len, article, index;
 
                 for (i = 0, len = data.articles.length; i < len; i++) {
                     article = data.articles[i];
@@ -323,7 +324,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
                 return;
             }
 
-            var Wanted = this.$articles.find(function (Article) {
+            const Wanted = this.$articles.find(function (Article) {
                 return Article.getAttribute('position') === position;
             });
 
@@ -597,7 +598,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
             Elm.getElements('.quiqqer-erp-sortableClone-placeholder').destroy();
 
             elements.each(function (Node) {
-                var Article = QUI.Controls.getById(Node.get('data-quiid'));
+                const Article = QUI.Controls.getById(Node.get('data-quiid'));
 
                 Article.removeEvents({
                     onSetPosition: self.$onArticleSetPosition
@@ -739,19 +740,19 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
          * @param {Object} EditArticle - package/quiqqer/erp/bin/backend/controls/articles/Article
          */
         $onArticleEditCustomFields: function (EditArticle) {
-            var ArticleCustomFields = EditArticle.getAttribute('customFields');
-            var FieldValues = {};
+            const ArticleCustomFields = EditArticle.getAttribute('customFields');
+            const FieldValues = {};
 
             for (const [fieldId, FieldData] of Object.entries(ArticleCustomFields)) {
                 FieldValues[fieldId] = FieldData.value;
             }
 
-            var AddProductControl = new AddProductWindow({
+            const AddProductControl = new AddProductWindow({
                 fieldValues: FieldValues,
                 editAmount : false
             });
 
-            var productId = EditArticle.getAttribute('id');
+            const productId = EditArticle.getAttribute('id');
 
             AddProductControl.openProductSettings(productId).then((ArticleData) => {
                 if (!ArticleData) {
@@ -774,7 +775,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
 
                 EditArticle.setAttribute('customFields', NewArticleCustomFields);
 
-                var NewArticle = new Article(EditArticle.getAttributes());
+                const NewArticle = new Article(EditArticle.getAttributes());
 
                 this.replaceArticle(NewArticle, EditArticle.getAttribute('position'));
             });
@@ -793,7 +794,7 @@ define('package/quiqqer/erp/bin/backend/controls/articles/ArticleList', [
          * refresh the brutto / netto switch display
          */
         $refreshNettoBruttoDisplay: function () {
-            var SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc');
+            const SwitchDesc = this.$Elm.getElement('.quiqqer-erp-backend-erpItems-container-switch-desc');
 
             if (this.getAttribute('nettoinput')) {
                 SwitchDesc.set('html', QUILocale.get(lg, 'control.articleList.netto.message'));
-- 
GitLab