You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ak...@apache.org on 2019/02/25 16:49:45 UTC

[ignite] branch master updated: IGNITE-11338 Web Console: Fixed edit mode of "list-editable" component.

This is an automated email from the ASF dual-hosted git repository.

akuznetsov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git


The following commit(s) were added to refs/heads/master by this push:
     new b0bc736  IGNITE-11338 Web Console: Fixed edit mode of "list-editable" component.
b0bc736 is described below

commit b0bc736924f49baf820df5682285e2041005b943
Author: Ilya Borisov <kl...@gmail.com>
AuthorDate: Mon Feb 25 23:49:30 2019 +0700

    IGNITE-11338 Web Console: Fixed edit mode of "list-editable" component.
---
 .../{component.js => component.ts}                 | 27 ++-----
 .../{index.js => index.ts}                         |  0
 .../{directive.js => directive.ts}                 | 31 +++-----
 .../list-editable-one-way/{index.js => index.ts}   |  0
 .../{directives.js => directives.ts}               | 25 ++-----
 .../{index.js => index.ts}                         |  0
 .../{directive.js => directive.ts}                 | 27 +++----
 .../{index.js => index.ts}                         |  0
 .../list-editable/{controller.js => controller.ts} | 83 ++++++++++++----------
 .../list-editable/{index.js => index.ts}           |  0
 .../app/components/list-editable/template.pug      | 14 ++--
 11 files changed, 87 insertions(+), 120 deletions(-)

diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.ts
similarity index 79%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.ts
index 84ee1e8..793270f 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/component.ts
@@ -22,33 +22,20 @@ import './style.scss';
 
 /**
  * Adds "add new item" button to list-editable-no-items slot and after list-editable
- * @type {ng.IComponentController}
  */
-export class ListEditableAddItemButton {
+export class ListEditableAddItemButton<T> {
     /** 
      * Template for button that's inserted after list-editable
-     * @type {string}
      */
-    static hasItemsTemplate = hasItemsTemplate;
-    /** @type {ListEditable} */
-    _listEditable;
-    /** @type {string} */
-    labelSingle;
-    /** @type {string} */
-    labelMultiple;
-    /** @type {ng.ICompiledExpression} */
-    _addItem;
+    static hasItemsTemplate: string = hasItemsTemplate;
+    _listEditable: ListEditable<T>;
+    labelSingle: string;
+    labelMultiple: string;
+    _addItem: ng.ICompiledExpression;
 
     static $inject = ['$compile', '$scope'];
 
-    /**
-     * @param {ng.ICompileService} $compile
-     * @param {ng.IScope} $scope
-     */
-    constructor($compile, $scope) {
-        this.$compile = $compile;
-        this.$scope = $scope;
-    }
+    constructor(private $compile: ng.ICompileService, private $scope: ng.IScope) {}
 
     $onDestroy() {
         this._listEditable = this._hasItemsButton = null;
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.ts
similarity index 100%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-add-item-button/index.ts
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.ts
similarity index 54%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.ts
index 320791b..91b0441 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/directive.ts
@@ -16,10 +16,9 @@
  */
 
 import isMatch from 'lodash/isMatch';
-import {default as ListEditableController} from '../../controller';
+import {default as ListEditableController, ID} from '../../controller';
 
-/** @type {ng.IDirectiveFactory} */
-export default function listEditableOneWay() {
+export default function listEditableOneWay(): ng.IDirective {
     return {
         require: {
             list: 'listEditable'
@@ -28,26 +27,18 @@ export default function listEditableOneWay() {
             onItemChange: '&?',
             onItemRemove: '&?'
         },
-        controller: class Controller {
-            /** @type {ListEditableController} */
-            list;
-            /** @type {ng.ICompiledExpression} onItemChange */
-            onItemChange;
-            /** @type {ng.ICompiledExpression} onItemRemove */
-            onItemRemove;
+        controller: class Controller<T> {
+            list: ListEditableController<T>;
+            onItemChange: ng.ICompiledExpression;
+            onItemRemove: ng.ICompiledExpression;
 
-            static $inject = ['$scope'];
-            /**
-             * @param {ng.IScope} $scope
-             */
-            constructor($scope) {
-                this.$scope = $scope;
-            }
             $onInit() {
-                this.list.save = (item, index) => {
-                    if (!isMatch(this.list.ngModel.$viewValue[index], item)) this.onItemChange({$event: item});
+                this.list.save = (item: T, id: ID) => {
+                    if (!isMatch(this.list.getItem(id), item)) this.onItemChange({$event: item});
                 };
-                this.list.remove = (index) => this.onItemRemove({$event: this.list.ngModel.$viewValue[index]});
+                this.list.remove = (id: ID) => this.onItemRemove({
+                    $event: this.list.getItem(id)
+                });
             }
         }
     };
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.ts
similarity index 100%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-one-way/index.ts
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.ts
similarity index 77%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.ts
index f408647..b3cab9e 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/directives.ts
@@ -15,21 +15,17 @@
  * limitations under the License.
  */
 
-import {default as ListEditableController} from '../../controller';
+import {default as ListEditableController, ID, ItemScope} from '../../controller';
+import {ListEditableTransclude} from '../list-editable-transclude/directive';
 
 const CUSTOM_EVENT_TYPE = '$ngModel.change';
 
 /** 
  * Emits $ngModel.change event on every ngModel.$viewValue change
- * @type {ng.IDirectiveFactory}
  */
-export function ngModel() {
+export function ngModel<T>(): ng.IDirective {
     return {
-        /**
-         * @param {JQLite} el
-         * @param {ng.INgModelController} ngModel
-         */
-        link(scope, el, attr, {ngModel, list}) {
+        link(scope, el, attr, {ngModel, list}: {ngModel: ng.INgModelController, list?: ListEditableController<T>}) {
             if (!list)
                 return;
 
@@ -45,17 +41,10 @@ export function ngModel() {
 }
 /** 
  * Triggers $ctrl.save when any ngModel emits $ngModel.change event
- * @type {ng.IDirectiveFactory}
  */
-export function listEditableTransclude() {
+export function listEditableTransclude<T>(): ng.IDirective {
     return {
-        /**
-         * @param {ng.IScope} scope
-         * @param {JQLite} el
-         * @param {ng.IAttributes} attr
-         * @param {ListEditableController} list
-         */
-        link(scope, el, attr, {list, transclude}) {
+        link(scope: ItemScope<T>, el, attr, {list, transclude}: {list?: ListEditableController<T>, transclude: ListEditableTransclude<T>}) {
             if (attr.listEditableTransclude !== 'itemEdit')
                 return;
 
@@ -65,7 +54,7 @@ export function listEditableTransclude() {
             let listener = (e) => {
                 e.stopPropagation();
                 scope.$evalAsync(() => {
-                    if (scope.form.$valid) list.save(scope.item, transclude.$index);
+                    if (scope.form.$valid) list.save(scope.item, list.id(scope.item, transclude.$index));
                 });
             };
 
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.ts
similarity index 100%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-save-on-changes/index.ts
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.ts
similarity index 89%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.ts
index 36750ae..272a423 100644
--- a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.js
+++ b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/directive.ts
@@ -15,38 +15,29 @@
  * limitations under the License.
  */
 
-// eslint-disable-next-line
-import {default as ListEditable} from '../../controller';
+import {default as ListEditable, ItemScope} from '../../controller';
+
+type TranscludedScope<T> = {$form: ng.IFormController, $item?: T} & ng.IScope
 
 /**
  * Transcludes list-editable slots and proxies item and form scope values to the slot scope,
  * also provides a way to retrieve internal list-editable ng-repeat $index by controller getter.
  * User can provide an alias for $item by setting item-name attribute on transclusion slot element.
  */
-export class ListEditableTransclude {
+export class ListEditableTransclude<T> {
     /**
      * Transcluded slot name.
-     *
-     * @type {string}
      */
-    slot;
+    slot: string;
 
-    /**
-     * List-editable controller.
-     *
-     * @type {ListEditable}
-     */
-    list;
+    list: ListEditable<T>;
 
     static $inject = ['$scope', '$element'];
 
-    constructor($scope, $element) {
-        this.$scope = $scope;
-        this.$element = $element;
-    }
+    constructor(private $scope: ItemScope<T>, private $element: JQLite) {}
 
     $postLink() {
-        this.list.$transclude((clone, transcludedScope) => {
+        this.list.$transclude((clone, transcludedScope: TranscludedScope<T>) => {
             // Ilya Borisov: at first I tried to use a slave directive to get value from
             // attribute and set it to ListEditableTransclude controller, but it turns out
             // this directive would run after list-editable-transclude, so that approach
@@ -98,8 +89,6 @@ export class ListEditableTransclude {
 
     /**
      * Returns list-editable ng-repeat $index.
-     *
-     * @returns {number}
      */
     get $index() {
         if (!this.$scope)
diff --git a/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/index.js b/modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/index.ts
similarity index 100%
rename from modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/index.js
rename to modules/web-console/frontend/app/components/list-editable/components/list-editable-transclude/index.ts
diff --git a/modules/web-console/frontend/app/components/list-editable/controller.js b/modules/web-console/frontend/app/components/list-editable/controller.ts
similarity index 58%
rename from modules/web-console/frontend/app/components/list-editable/controller.js
rename to modules/web-console/frontend/app/components/list-editable/controller.ts
index d1b8900..e870e82 100644
--- a/modules/web-console/frontend/app/components/list-editable/controller.js
+++ b/modules/web-console/frontend/app/components/list-editable/controller.ts
@@ -17,34 +17,40 @@
 
 import _ from 'lodash';
 
-/** @type {ng.IComponentController} */
-export default class {
-    /** @type {ng.INgModelController} */
-    ngModel;
+export interface ListEditableNgModel<T> extends ng.INgModelController {
+    $viewValue: T[],
+    editListItem(item: T): void,
+    editListIndex(index: number): void
+}
+
+export type ID = (string | number) & {tag: 'ItemID'}
 
+export type ItemScope<T> = {$index: number, item: T, form: ng.IFormController} & ng.IScope
+
+export default class ListEditable<T extends {_id?: any}> {
     static $inject = ['$animate', '$element', '$transclude', '$timeout'];
 
-    /**
-     * @param {ng.animate.IAnimateService} $animate
-     * @param {JQLite} $element
-     * @param {ng.ITranscludeFunction} $transclude
-     * @param {ng.ITimeoutService} $timeout
-     */
-    constructor($animate, $element, $transclude, $timeout) {
+    constructor(
+        $animate: ng.animate.IAnimateService,
+        public $element: JQLite,
+        public $transclude: ng.ITranscludeFunction,
+        private $timeout: ng.ITimeoutService
+    ) {
         $animate.enabled($element, false);
-        this.$transclude = $transclude;
-        this.$element = $element;
-        this.$timeout = $timeout;
         this.hasItemView = $transclude.isSlotFilled('itemView');
 
-        this._cache = {};
+        this._cache = new Map();
     }
 
-    $index(item, $index) {
-        if (item._id)
-            return item._id;
+    ngModel: ListEditableNgModel<T>;
+    hasItemView: boolean
+    private _cache: Map<ID, T>
+
+    id(item: T | undefined, index: number): ID {
+        if (item && item._id)
+            return item._id as ID;
 
-        return $index;
+        return index as ID;
     }
 
     $onDestroy() {
@@ -57,7 +63,7 @@ export default class {
         };
         this.ngModel.editListItem = (item) => {
             this.$timeout(() => {
-                this.startEditView(this.ngModel.$viewValue.indexOf(item));
+                this.startEditView(this.id(item, this.ngModel.$viewValue.indexOf(item)));
                 // For some reason required validator does not re-run after adding an item,
                 // the $validate call fixes the issue.
                 this.ngModel.$validate();
@@ -65,7 +71,7 @@ export default class {
         };
         this.ngModel.editListIndex = (index) => {
             this.$timeout(() => {
-                this.startEditView(index);
+                this.startEditView(this.id(this.ngModel.$viewValue[index], index));
                 // For some reason required validator does not re-run after adding an item,
                 // the $validate call fixes the issue.
                 this.ngModel.$validate();
@@ -73,31 +79,36 @@ export default class {
         };
     }
 
-    save(data, idx) {
-        this.ngModel.$setViewValue(this.ngModel.$viewValue.map((v, i) => i === idx ? _.cloneDeep(data) : v));
+    save(item: T, id: ID) {
+        this.ngModel.$setViewValue(
+            this.ngModel.$viewValue.map((v, i) => this.id(v, i) === id ? _.cloneDeep(item) : v)
+        );
     }
 
-    revert(idx) {
-        delete this._cache[idx];
+    remove(id: ID): void {
+        this.ngModel.$setViewValue(this.ngModel.$viewValue.filter((v, i) => this.id(v, i) !== id));
     }
 
-    remove(idx) {
-        this.ngModel.$setViewValue(this.ngModel.$viewValue.filter((v, i) => i !== idx));
+    isEditView(id: ID): boolean {
+        return this._cache.has(id);
     }
 
-    isEditView(idx) {
-        return this._cache.hasOwnProperty(idx);
+    getEditView(id: ID): T {
+        return this._cache.get(id);
     }
 
-    getEditView(idx) {
-        return this._cache[idx];
+    getItem(id: ID): T {
+        return this.ngModel.$viewValue.find((v, i) => this.id(v, i) === id);
     }
 
-    startEditView(idx) {
-        this._cache[idx] = _.cloneDeep(this.ngModel.$viewValue[idx]);
+    startEditView(id: ID) {
+        this._cache.set(
+            id,
+            _.cloneDeep(this.getItem(id))
+        );
     }
 
-    stopEditView(data, idx, form) {
+    stopEditView(data: T, id: ID, form: ng.IFormController) {
         // By default list-editable saves only valid values, but if you specify {allowInvalid: true}
         // ng-model-option, then it will always save. Be careful and pay extra attention to validation
         // when doing so, it's an easy way to miss invalid values this way.
@@ -106,8 +117,8 @@ export default class {
         if (!form.$valid && !this.ngModel.$options.getOption('allowInvalid'))
             return;
 
-        delete this._cache[idx];
+        this._cache.delete(id);
 
-        this.save(data, idx);
+        this.save(data, id);
     }
 }
diff --git a/modules/web-console/frontend/app/components/list-editable/index.js b/modules/web-console/frontend/app/components/list-editable/index.ts
similarity index 100%
rename from modules/web-console/frontend/app/components/list-editable/index.js
rename to modules/web-console/frontend/app/components/list-editable/index.ts
diff --git a/modules/web-console/frontend/app/components/list-editable/template.pug b/modules/web-console/frontend/app/components/list-editable/template.pug
index b52bfd2..19a9507 100644
--- a/modules/web-console/frontend/app/components/list-editable/template.pug
+++ b/modules/web-console/frontend/app/components/list-editable/template.pug
@@ -16,9 +16,9 @@
 
 .le-body
     .le-row(
-        ng-repeat='item in $ctrl.ngModel.$viewValue track by $ctrl.$index(item, $index)'
+        ng-repeat='item in $ctrl.ngModel.$viewValue track by $ctrl.id(item, $index)'
         ng-class=`{
-            'le-row--editable': $ctrl.isEditView($index),
+            'le-row--editable': $ctrl.isEditView($ctrl.id(item, $index)),
             'le-row--has-item-view': $ctrl.hasItemView
         }`)
 
@@ -30,20 +30,20 @@
             span {{ $index+1 }}
 
         .le-row-item
-            .le-row-item-view(ng-if='$ctrl.hasItemView && !$ctrl.isEditView($index)' ng-click='$ctrl.startEditView($index);')
+            .le-row-item-view(ng-if='$ctrl.hasItemView && !$ctrl.isEditView($ctrl.id(item, $index))' ng-click='$ctrl.startEditView($ctrl.id(item, $index))')
                 div(list-editable-transclude='itemView')
             div(
-                ng-if='!$ctrl.hasItemView || $ctrl.isEditView($index)'
-                ignite-on-focus-out='$ctrl.stopEditView(item, $index, form);'
+                ng-if='!$ctrl.hasItemView || $ctrl.isEditView($ctrl.id(item, $index))'
+                ignite-on-focus-out='$ctrl.stopEditView(item, $ctrl.id(item, $index), form)'
                 ignite-on-focus-out-ignored-classes='bssm-click-overlay bssm-item-text bssm-item-button'
             )
-                .le-row-item-view(ng-show='$ctrl.hasItemView' ng-init='$ctrl.startEditView($index);item = $ctrl.getEditView($index);')
+                .le-row-item-view(ng-show='$ctrl.hasItemView' ng-init='$ctrl.startEditView($ctrl.id(item, $index));item = $ctrl.getEditView($ctrl.id(item, $index))')
                     div(list-editable-transclude='itemView')
                 .le-row-item-edit(ng-form name='form')
                     div(list-editable-transclude='itemEdit')
 
         .le-row-cross
-            button.btn-ignite.btn-ignite--link-dashed-secondary(type='button' ng-click='$ctrl.remove($index)')
+            button.btn-ignite.btn-ignite--link-dashed-secondary(type='button' ng-click='$ctrl.remove($ctrl.id(item, $index))')
                 svg(ignite-icon='cross')
 
     .le-row(ng-hide='$ctrl.ngModel.$viewValue.length')