Browse Source

HUE-7140 [editor] Add select variables

jdesjean 8 years ago
parent
commit
a9ad470100

+ 76 - 1
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -6331,6 +6331,81 @@
     init: function (element, valueAccessor) {
       $(element).jHueRowSelector();
     }
-  }
+  };
+
+  //https://stackoverflow.com/questions/19865364/knockoutjs-linking-value-from-a-input-to-a-datalist-value
+  ko.bindingHandlers.datalist = (function () {
+    function getVal(rawItem, prop) {
+      var item = ko.unwrap(rawItem);
+      return item && prop ? ko.unwrap(item[prop]) : item;
+    }
+
+    function findItem(options, prop, ref) {
+      return ko.utils.arrayFirst(options, function (item) {
+        return ref === getVal(item, prop);
+      });
+    }
+    return {
+      init: function (element, valueAccessor, allBindingsAccessor) {
+        var setup = valueAccessor(),
+          textProperty = ko.unwrap(setup.optionsText),
+          valueProperty = ko.unwrap(setup.optionsValue),
+          dataItems = ko.unwrap(setup.options),
+          myValue = setup.value,
+          koValue = allBindingsAccessor().value,
+          datalist = document.createElement("DATALIST");
+
+        // create an associated <datalist> element
+        datalist.id = element.getAttribute("list");
+        document.body.appendChild(datalist);
+
+        // when the value is changed, write to the associated myValue observable
+        function onNewValue(newVal) {
+          var dataItems = ko.unwrap(setup.options),
+            selectedItem = findItem(dataItems, textProperty, newVal),
+            newValue = selectedItem ? getVal(selectedItem, valueProperty) : newVal;
+
+          if (ko.isWriteableObservable(myValue)) {
+            myValue(newValue);
+          }
+        }
+
+        // listen for value changes
+        // - either via KO's value binding (preferred) or the change event
+        if (ko.isSubscribable(koValue)) {
+          koValue.subscribe(onNewValue);
+        } else {
+          var event = allBindingsAccessor().valueUpdate === "afterkeydown" ? "input" : "change";
+          ko.utils.registerEventHandler(element, event, function () {
+            onNewValue(this.value);
+          });
+        }
+
+        // init the element's value
+        // - either via the myValue observable (preferred) or KO's value binding
+        if (ko.isObservable(myValue) && myValue()) {
+          var selectedItem = findItem(dataItems, valueProperty, myValue());
+          element.value = selectedItem ? getVal(selectedItem, textProperty) : myValue();
+        } else if (ko.isObservable(koValue) && koValue()) {
+          onNewValue(koValue());
+        }
+      },
+      update: function (element, valueAccessor) {
+        var setup = valueAccessor(),
+          datalist = element.list,
+          dataItems = ko.unwrap(setup.options),
+          textProperty = ko.unwrap(setup.optionsText);
+
+        // rebuild list of options when an underlying observable changes
+        datalist.innerHTML = "";
+        ko.utils.arrayForEach(dataItems, function (item) {
+          var option = document.createElement("OPTION");
+          option.value = getVal(item, textProperty);
+          datalist.appendChild(option);
+        });
+        ko.utils.triggerEvent(element, "change");
+      }
+    };
+  })();
 
 })();

+ 19 - 3
desktop/libs/notebook/src/notebook/static/notebook/js/notebook.ko.js

@@ -544,7 +544,9 @@ var EditorViewModel = (function() {
     });
     if (snippet.variables) {
       snippet.variables.forEach(function (variable) {
-        variable.defaultValue = variable.defaultValue || '';
+        variable.meta = (typeof variable.defaultValue === "object" && variable.defaultValue) || {type: "text", placeholder: ""};
+        variable.value = variable.value || "";
+        delete variable.defaultValue;
       });
     }
     self.variables = ko.mapping.fromJS(typeof snippet.variables != "undefined" && snippet.variables != null ? snippet.variables : []);
@@ -612,6 +614,18 @@ var EditorViewModel = (function() {
 
       return params;
     };
+    function getJSONLength (index) {
+      //all bracket pairs
+      if (this.charAt(index) != "{") return 0;
+      var nOpenBracket = 1, start = index, i;
+      for (i = index + 1; i < this.length; i++) {
+        var currentChar = this.charAt(i);
+        if (currentChar === "{") nOpenBracket++;
+        else if (currentChar === "}") nOpenBracket--;
+        if (nOpenBracket <= 0) break;
+      }
+      return i - start + 1;
+    };
     self.variableNames = ko.computed(function () {
       var match, matches = {};
       if (self.type() == 'pig') {
@@ -633,7 +647,9 @@ var EditorViewModel = (function() {
         }
       }
       return Object.keys(matches).map(function (match) {
-        return { name: match, defaultValue: matches[match] };
+        var isMatchObject = typeof matches[match] === "object";
+        var meta = isMatchObject ? matches[match] : {type: "text", placeholder: matches[match]};
+        return {name: match, meta: meta};
       });
     });
     self.variableValues = {};
@@ -648,7 +664,7 @@ var EditorViewModel = (function() {
       }, self.variableValues);
       if (needsMore) {
         for (var i = 0, length = Math.abs(diffLengthVariables); i < length; i++) {
-          self.variables.push(ko.mapping.fromJS({ 'name': '', 'value': '', 'defaultValue': '' }));
+          self.variables.push(ko.mapping.fromJS({ "name": "", "value": "", "meta": {type: "text", placeholder: ""}}));
         }
       } else if (needsLess) {
         self.variables.splice(self.variables().length - diffLengthVariables, diffLengthVariables);

+ 9 - 1
desktop/libs/notebook/src/notebook/templates/editor_components.mako

@@ -1225,7 +1225,15 @@ ${ sqlSyntaxDropdown.sqlSyntaxDropdown() }
       <li>
         <div class="input-prepend margin-top-10">
           <span class="muted add-on" data-bind="text: name"></span>
-          <input class="input-medium" type="text" data-bind="value: value, attr: { placeholder: defaultValue() || '${ _ko('Variable value') }' }, valueUpdate: 'afterkeydown', autogrowInput: { minWidth: 150, maxWidth: 270, comfortZone: 15 }, event: { 'keydown': function (context, e){ if ((e.ctrlKey || e.metaKey) && e.which === 13) { $parent.ace().commands.commands['execute'].exec(); } return true; } }">
+          <!-- ko if: meta.type() == 'text' -->
+          <input class="input-medium" type="text" data-bind="value: value, attr: { placeholder: meta.placeholder() || '${ _ko('Variable value') }' }, valueUpdate: 'afterkeydown', autogrowInput: { minWidth: 150, maxWidth: 270, comfortZone: 15 }, event: { 'keydown': function (context, e){ if ((e.ctrlKey || e.metaKey) && e.which === 13) { $parent.ace().commands.commands['execute'].exec(); } return true; } }">
+          <!-- /ko -->
+          <!-- ko if: meta.type() == 'select' && !('options' in document.createElement('datalist')) -->
+          <select data-bind="options: meta.options(), optionsText: 'text', optionsValue:'value', value: value, attr: { placeholder: meta.placeholder() || '${ _ko('Variable value') }' }, event: { 'keydown': function (context, e){ if ((e.ctrlKey || e.metaKey) && e.which === 13) { $parent.ace().commands.commands['execute'].exec(); } return true; } }"/>
+          <!-- /ko -->
+          <!-- ko if: meta.type() == 'select' && 'options' in document.createElement('datalist') -->
+          <input list="input-medium" type="text" data-bind="datalist: { options: meta.options(), optionsText: 'text', optionsValue: 'value', value: value }, valueUpdate: 'afterkeydown', autogrowInput: { minWidth: 150, maxWidth: 270, comfortZone: 15 }, attr: { placeholder: meta.placeholder() || '${ _ko('Variable value') }' }, event: { 'keydown': function (context, e){ if ((e.ctrlKey || e.metaKey) && e.which === 13) { $parent.ace().commands.commands['execute'].exec(); } return true; } }" />
+          <!-- /ko -->
         </div>
       </li>
     </ul>