Procházet zdrojové kódy

HUE-4967 [editor] Add edit mode for navigator tags

Johan Ahlen před 9 roky
rodič
revize
3545f02

+ 40 - 6
desktop/core/src/desktop/static/desktop/ext/css/selectize.css

@@ -154,6 +154,36 @@
   border-radius: 3px;
 }
 
+.selectize-read-only.multi .selectize-input {
+  cursor: default;
+  border-color: transparent;
+}
+
+.selectize-actions {
+  z-index: 10000;
+  font-size: 15px;
+  position: absolute;
+  top: 1px;
+  right: 3px;
+  opacity: 0;
+  transition: opacity 0.2s ease;
+}
+
+.selectize-actions i {
+  cursor: pointer;
+  color: #999;
+  transition: color 0.2s linear;
+  margin-left: 2px;
+}
+
+.selectize-actions i:hover {
+  color: #338BB8;
+}
+
+.selectize-actions-visible {
+  opacity: 1;
+}
+
 .selectize-control.multi .selectize-input.has-items {
   padding: 6px 8px 3px;
   box-shadow: none;
@@ -192,16 +222,20 @@
   cursor: pointer;
   margin: 0 3px 3px 0;
   padding: 2px 6px;
-  background: #DBE8F1;
-  color: #338BB8;
-  border: 0 solid #DBE8F1;
+  background: #338BB8;
+  color: #FFF;
+  border: 0 solid #338BB8;
   border-radius: 5px
 }
 
+.selectize-read-only.multi .selectize-input > div {
+  cursor: default;
+}
+
 .selectize-control.multi .selectize-input > div.active {
-  background: #338BB8;
-  color: #DBE8F1;
-  border: 0 solid #DBE8F1;
+  background: #DBE8F1;
+  color: #338BB8;
+  border: 0 solid #338BB8;
 }
 
 .selectize-control.multi .selectize-input.disabled > div,

+ 66 - 4
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -25,12 +25,13 @@
   ko.bindingHandlers.tagEditor = {
     init: function (element, valueAccessor) {
       var options = valueAccessor();
+      var $element = $(element);
 
       options = $.extend({
-        plugins: ['restore_on_backspace', 'remove_button'],
-        options: $.map(options.initialTags, function (value) { return { value: value, text: value } }),
+        plugins: ['remove_button'],
+        options: $.map(options.setTags(), function (value) { return { value: value, text: value } }),
         delimiter: ',',
-        items: options.initialTags,
+        items: options.setTags(),
         closeAfterSelect: true,
         persist: true,
         preload: true,
@@ -42,7 +43,68 @@
         }
       }, options);
 
-      $(element).selectize(options)[0].selectize;
+      var $readOnlyContainer = $('<div>').hide().addClass('selectize-control selectize-read-only multi').attr('style', $element.attr('style')).insertAfter($(element));
+
+      $readOnlyContainer.on('mouseover', function () {
+        $readOnlyContainer.find('.selectize-actions').addClass('selectize-actions-visible');
+      });
+
+      $readOnlyContainer.on('mouseout', function () {
+        $readOnlyContainer.find('.selectize-actions').removeClass('selectize-actions-visible');
+      });
+
+      $element.hide();
+
+      var currentSelectize;
+
+      var showEdit = function () {
+        options.options = $.map(options.setTags(), function (value) { return { value: value, text: value } }),
+        currentSelectize = $element.selectize(options)[0].selectize;
+        $readOnlyContainer.hide();
+        $element.next().find('.selectize-input').css('padding-right', '25px');
+        $element.next().find('input').focus();
+        var $editActions = $('<div>').addClass('selectize-actions selectize-actions-visible').appendTo($element.next());
+        $('<i>').addClass('fa fa-check').click(function () {
+          options.onSave(currentSelectize.getValue());
+          showReadOnly();
+        }).appendTo($editActions);
+        $('<i>').addClass('fa fa-close').click(function () {
+          showReadOnly();
+        }).appendTo($editActions);
+
+        $element.next().on('mouseover', function () {
+          $editActions.addClass('selectize-actions-visible');
+        });
+
+        $element.next().on('mouseout', function () {
+          $editActions.removeClass('selectize-actions-visible');
+        });
+      };
+
+      var showReadOnly = function () {
+        if (currentSelectize) {
+          currentSelectize.destroy();
+          $element.hide();
+        }
+        $readOnlyContainer.empty();
+        var $readOnlyInner = $('<div>').addClass('selectize-input items not-full has-options has-items').appendTo($readOnlyContainer);
+        if (options.setTags().length > 0) {
+          options.setTags().forEach(function (tag) {
+            $('<div>').addClass('item-read-only').text(tag).appendTo($readOnlyInner);
+          });
+        } else {
+          $('<input type="text">').attr('placeholder', options.placeholder).appendTo($readOnlyInner);
+        }
+
+        var $readOnlyActions = $('<div>').addClass('selectize-actions').appendTo($readOnlyContainer);
+        $readOnlyContainer.show();
+
+        $('<i>').addClass('fa fa-edit').click(function () {
+          showEdit();
+        }).appendTo($readOnlyActions);
+      };
+
+      showReadOnly();
     }
   };
 

+ 29 - 8
desktop/core/src/desktop/templates/sql_context_popover.mako

@@ -1044,7 +1044,7 @@ from metadata.conf import has_navigator
       </div>
       <div class="sql-context-flex-fill sql-columns-table" style="position:relative; height: 100%; overflow-y: auto;">
         <div style="margin: 10px">
-          <textarea style="width: 100%" data-bind="tagEditor: { placeholder: '${_ko('Enter tags...')}', initialTags: currentTags, onItemAdd: onTagAdd, onItemRemove: onTagRemove, load: loadTags  }"></textarea>
+          <textarea style="width: 100%" data-bind="tagEditor: { placeholder: '${_ko('Enter tags...')}', setTags: currentTags, onSave: onSave, load: loadTags  }"></textarea>
         </div>
       </div>
     </div>
@@ -1066,7 +1066,7 @@ from metadata.conf import has_navigator
         var self = this;
         var apiHelper = ApiHelper.getInstance();
 
-        self.currentTags = params.entity.tags;
+        self.currentTags = ko.observableArray(params.entity.tags);
         self.allTags = ko.observableArray();
 
         var fetchAllTags = function () {
@@ -1080,16 +1080,37 @@ from metadata.conf import has_navigator
         fetchAllTags();
 
         self.loadTags = function (query, callback) {
-          console.log(self.allTags());
           callback($.map(self.allTags(), function (tag) { return { value: tag, text: tag }}));
         };
 
-        self.onTagAdd = function (value) {
-          apiHelper.addNavTags(params.entity.identity, [value]);
-        };
+        self.onSave = function (value) {
+          var newTags = value.split(',');
+          var tagsToRemove = [];
+          var tagsToAdd = [];
+          var tagIndex = {};
+          self.currentTags().forEach(function (tag) {
+            tagIndex[tag] = false;
+          });
+          newTags.forEach(function (newTag) {
+            if (typeof tagIndex[newTag] !== 'undefined') {
+              tagIndex[newTag] = true;
+            } else {
+              tagsToAdd.push(newTag);
+            }
+          });
+          Object.keys(tagIndex).forEach(function (oldTag) {
+            if (! tagIndex[oldTag]) {
+              tagsToRemove.push(oldTag);
+            }
+          });
 
-        self.onTagRemove = function (value) {
-          apiHelper.deleteNavTags(params.entity.identity, [value]);
+          if (tagsToAdd.length > 0) {
+            apiHelper.addNavTags(params.entity.identity, tagsToAdd);
+          }
+          if (tagsToRemove.length > 0) {
+            apiHelper.deleteNavTags(params.entity.identity, tagsToRemove);
+          }
+          self.currentTags(newTags);
         };
       }