You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2021/06/18 19:38:21 UTC

[airavata-django-portal] 04/20: AIRAVATA-3453 Integrated jquery-textcomplete plugin

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

machristie pushed a commit to branch airavata-3453
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git

commit e54afd181f296ec1985f98c959c04226adb261ee
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Mon May 3 11:15:17 2021 -0400

    AIRAVATA-3453 Integrated jquery-textcomplete plugin
    
    To get the plugin and the hide/show logic to work
    I needed to switch from Vue slots to native slots
    which are now dynamically generated for exp
    inputs in ExperimentEditor.
---
 django_airavata/apps/workspace/package.json        |   1 +
 .../jquery.textcomplete.css                        |  33 ++++
 .../jquery.textcomplete.min.js                     |   3 +
 .../js/web-components/ExperimentEditor.vue         |  40 +++--
 .../django_airavata_workspace/supcrtbl2.html       | 180 +++++++++++++++++++--
 django_airavata/apps/workspace/yarn.lock           |   5 +
 6 files changed, 236 insertions(+), 26 deletions(-)

diff --git a/django_airavata/apps/workspace/package.json b/django_airavata/apps/workspace/package.json
index 6d227b1..883c65d 100644
--- a/django_airavata/apps/workspace/package.json
+++ b/django_airavata/apps/workspace/package.json
@@ -37,6 +37,7 @@
     "@vue/cli-plugin-unit-jest": "^3.3.0",
     "@vue/cli-service": "^3.1.1",
     "@vue/test-utils": "^1.0.0-beta.28",
+    "@vue/web-component-wrapper": "^1.3.0",
     "babel-core": "7.0.0-bridge.0",
     "babel-eslint": "^10.0.1",
     "babel-jest": "^23.6.0",
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.css b/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.css
new file mode 100644
index 0000000..37a761b
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.css
@@ -0,0 +1,33 @@
+/* Sample */
+
+.dropdown-menu {
+    border: 1px solid #ddd;
+    background-color: white;
+}
+
+.dropdown-menu li {
+    border-top: 1px solid #ddd;
+    padding: 2px 5px;
+}
+
+.dropdown-menu li:first-child {
+    border-top: none;
+}
+
+.dropdown-menu li:hover,
+.dropdown-menu .active {
+    background-color: rgb(110, 183, 219);
+}
+
+
+/* SHOULD not modify */
+
+.dropdown-menu {
+    list-style: none;
+    padding: 0;
+    margin: 0;
+}
+
+.dropdown-menu a:hover {
+    cursor: pointer;
+}
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.min.js b/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.min.js
new file mode 100644
index 0000000..ce1536d
--- /dev/null
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/jquery.textcomplete.min.js
@@ -0,0 +1,3 @@
+/*! jquery-textcomplete - v1.8.4 - 2017-08-29 */
+!function(a){if("function"==typeof define&&define.amd)define(["jquery"],a);else if("object"==typeof module&&module.exports){var b=require("jquery");module.exports=a(b)}else a(jQuery)}(function(a){if("undefined"==typeof a)throw new Error("jQuery.textcomplete requires jQuery");return+function(a){"use strict";var b=function(a){console.warn&&console.warn(a)},c=1;a.fn.textcomplete=function(d,e){var f=Array.prototype.slice.call(arguments);return this.each(function(){var g=this,h=a(this),i=h.da [...]
+//# sourceMappingURL=dist/jquery.textcomplete.min.map
\ No newline at end of file
diff --git a/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue
index fc36687..0de4bff 100644
--- a/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue
+++ b/django_airavata/apps/workspace/static/django_airavata_workspace/js/web-components/ExperimentEditor.vue
@@ -10,16 +10,12 @@
       </slot>
     </div>
     <template v-for="input in experiment.experimentInputs">
-      <div :key="input.name" @input="updateInputValue($event, input)">
-        <slot :name="input.name">
-          {{ input.name }}
-          <input
-            v-if="input.type.name == 'STRING'"
-            :name="`input:${input.name}`"
-            :value="input.value"
-          />
-        </slot>
-        <!-- TODO: add support for other input types -->
+      <div
+        :ref="input.name"
+        :key="input.name"
+        @input="updateInputValue($event, input)"
+      >
+      <!-- programmatically define slots as native slots (not Vue slots), see #mounted() -->
       </div>
     </template>
     <slot name="save-button">
@@ -48,12 +44,32 @@ export default {
       required: false,
     },
   },
-  async created() {
+  async created() {},
+  async mounted() {
     this.applicationModule = await getApplicationModule(this.applicationId);
     this.appInterface = await getApplicationInterfaceForModule(
       this.applicationId
     );
     this.experiment = await this.loadExperiment();
+    // vue-web-component-wrapper clones native slots and turns them into Vue
+    // slots which means they lose any event listeners and they basically aren't
+    // in the DOM any more.  As a workaround, programmatically create native
+    // slots. See also https://github.com/vuejs/vue-web-component-wrapper/issues/38
+    this.$nextTick(() => {
+      for (const input of this.experiment.experimentInputs) {
+        const slot = document.createElement("slot");
+        slot.setAttribute("name", input.name);
+        if (input.type.name === "STRING") {
+          slot.textContent = `${input.name} `;
+          const textInput = document.createElement("input");
+          textInput.setAttribute("type", "text");
+          textInput.setAttribute("value", input.value);
+          slot.appendChild(textInput);
+        }
+        // TODO: add support for other input types
+        this.$refs[input.name][0].append(slot);
+      }
+    });
   },
   data() {
     return {
@@ -105,7 +121,7 @@ export default {
         const defaultProjectId = await getDefaultProjectId();
         experiment.projectId = defaultProjectId;
         experiment.userConfigurationData.computationalResourceScheduling.resourceHostId =
-          "bigred3.uits.iu.edu_2141bf96-c458-4ecd-8759-aa3a08f31956";
+          "js-169-51.jetstream-cloud.org_6672e8fe-8d63-4bbe-8bf8-4ea04092e72f";
         this.$emit("loaded", experiment);
         return experiment;
       }
diff --git a/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html b/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html
index 0d9c78f..638c6ce 100644
--- a/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html
+++ b/django_airavata/apps/workspace/templates/django_airavata_workspace/supcrtbl2.html
@@ -8,6 +8,7 @@
 {% comment %} {% render_bundle 'chunk-vendors' 'css' 'WORKSPACE' %} {% endcomment %}
 {% comment %} {% render_bundle 'chunk-common' 'css' 'WORKSPACE' %} {% endcomment %}
 {% comment %} {% render_bundle 'adpf' 'css' 'WORKSPACE' %} {% endcomment %}
+	<link href="{% static 'django_airavata_workspace/jquery.textcomplete.css' %}" rel="stylesheet" type="text/css">
 {% endblock %}
 
 {% block content %}
@@ -178,31 +179,32 @@
 {% comment %} {% render_bundle 'chunk-common' 'js' 'WORKSPACE' %} {% endcomment %}
 {% comment %} {% render_bundle 'adpf' 'js' 'WORKSPACE' %} {% endcomment %}
 <script src="{% static 'django_airavata_workspace/wc/adpf.min.js' %}"></script>
+<script src="{% static 'django_airavata_workspace/jquery.textcomplete.min.js' %}"></script>
 <script>
 document.getElementById("experiment-editor").addEventListener('loaded', e => {
   const [experiment] = e.detail;
   for (const input of experiment.experimentInputs) {
-    // TODO: just iterate over the slotted inputs
-    const inputEl = document.querySelector(`[name="input:${input.name}"]`)
-    if (!inputEl) {
-      console.warn("Could not find input editor for ", input);
-    } else {
-      if (inputEl.type === 'radio') {
-        const radios = document.querySelectorAll(`[name="input:${input.name}"]`);
-        for (const radio of radios) {
+    const slotEl = document.querySelector(`[slot="${input.name}"]`);
+    // console.log("slotEl=", slotEl);
+    if (slotEl) {
+      const inputEls = slotEl.querySelectorAll('input');
+      // console.log("inputEls=", inputEls);
+      if (!inputEls || inputEls.length === 0) {
+        continue;
+      }
+      if (inputEls[0].type === 'text') {
+        inputEls[0].value = input.value;
+      } else if (inputEls[0].type === 'radio') {
+        for (radio of inputEls) {
           if (radio.value === input.value) {
-            // Have to set value with setAttribute so it is part of the DOM
-            // since the slot content doesn't appear to get added to the custom
-            // element until later. Setting as a property doesn't work.
-            radio.setAttribute("checked", "checked");
+            radio.checked = true;
             break;
           }
         }
-      } else if (inputEl.type === 'text') {
-        inputEl.setAttribute("value", input.value);
       }
     }
   }
+  resetViews();
 });
 function validateExperiment(event) {
   const [experiment] = event.detail;
@@ -213,5 +215,155 @@ function validateExperiment(event) {
   }
 }
 document.getElementById('experiment-editor').addEventListener('save', validateExperiment);
+
+$('document').ready(function() {
+  $('#reaction').textcomplete([{
+    match: /(^|\b)(\S{1,})$/,
+    search: function (term, callback) {
+      var words = ["ALMANDINE","ANDRADITE","GROSSULAR","KNORRINGITE","MAJORITE","PYROPE","SPESSARTINE","CLINOHUMITE","FAYALITE","FORSTERITE","MONTICELLITE","TEPHROITE","ANDALUSITE","KYANITE","Al-MULLITE","Si-MULLITE","Fe-CHLORITOID","Mg-CHLORITOID","Mn-CHLORITOID","Fe-STAUROLITE","Mg-STAUROLITE","Mn-STAUROLITE","HYDROXY-TOPAZ","AKERMANITE","JULGOLDITE(FeFe)","MERWINITE","PUMPELLYITE(FeAl)","PUMPELLYITE(MgAl)","RANKINITE","SPURRITE","TILLEYITE","ZIRCON","CLINOZOISITE","EPIDOTE(ORDERED)"," [...]
+      callback($.map(words, function (word) {
+        return word.toLowerCase().indexOf(term.toLowerCase()) === 0 ? word : null;
+      }));
+    },replace: function (word) {
+      return word + ' ';
+    }
+  }]);
+});
+
+function resetViews() {
+		$('#lipVapSat').hide();
+		$('#indVar').hide();
+		$('#tabulationBaric').hide();
+		$('#tabulationChoric').hide();
+		$('#table').hide();
+		$('#univariantCurve').hide();
+		$('#univariantCalc').hide();
+		$('#isochores').hide();
+		$('#temp').hide();
+		$('#dH2OTemp').hide();
+		$('#logK').hide();
+		$('#isotherms').hide();
+		$('#dH2O').hide();
+		$('#tempDH2O').hide();
+		$('#isobars').hide();
+		$('#logKBoundingTemp').hide();
+		$('#logKBoundingPres').hide();
+		$('#presTemp').hide();
+		$('#pres').hide();
+		$('#tempPres').hide();
+		$('#lipVapSatTemp').hide();
+		$('#lipVapSatPres').hide();
+		$('#submit').hide();
+		if($('input:radio[name=solventPhase]:checked').val() == "0"){
+			$('#indVar').show();
+			if($('input:radio[name=independentStateVar]:checked').val() == "0"){
+				$('#tabulationChoric').show();
+				if($('input:radio[name=tabulationChoricOption]:checked').val() == "0"){
+					$('#table').show();
+					if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+						$('#isochores').show();
+						$('#temp').show();
+						$('#submit').show();
+
+					}
+					else if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+						$('#dH2OTemp').show();
+						$('#submit').show();
+					}
+				}
+				else if($('input:radio[name=tabulationChoricOption]:checked').val() == "1"){
+					$('#table').show();
+					if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+						$('#isotherms').show();
+						$('#dH2O').show();
+						$('#submit').show();
+
+					}
+					else if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+						$('#tempDH2O').show();
+						$('#submit').show();
+					}
+				}
+			}
+			else if($('input:radio[name=independentStateVar]:checked').val() == "1"){
+				$('#univariantCurve').show();
+				if($('input:radio[name=univariantCurveOption]:checked').val() == "0"){
+					$('#univariantCalc').show();
+					if($('input:radio[name=univariantCalcOption]:checked').val() == "0") {
+							$('#isobars').show();
+							$('#logK').show();
+							$('#logKBoundingTemp').show();
+							$('#submit').show();
+					}
+					else if($('input:radio[name=univariantCalcOption]:checked').val() == "1"){
+							$('#isotherms').show();
+							$('#logK').show();
+							$('#logKBoundingPres').show();
+							$('#submit').show();
+					}
+				}
+				if($('input:radio[name=univariantCurveOption]:checked').val() == "1"){
+					$('#tabulationBaric').show();
+					if($('input:radio[name=tabulationBaricOption]:checked').val() == "0"){
+						$('#table').show();
+						if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+							$('#isobars').show();
+							$('#temp').show();
+							$('#submit').show();
+
+						}
+						else if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+							$('#presTemp').show();
+							$('#submit').show();
+						}
+					}
+					else if($('input:radio[name=tabulationBaricOption]:checked').val() == "1"){
+						$('#table').show();
+						if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+							$('#isotherms').show();
+							$('#pres').show();
+							$('#submit').show();
+						}
+						else if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+							$('#tempPres').show();
+							$('#submit').show();
+						}
+					}
+				}
+
+			}
+		}
+		else if($('input:radio[name=solventPhase]:checked').val() == "1"){
+			$('#lipVapSat').show();
+			if($('input:radio[name=lipVapSatVar]:checked').val() == "0"){
+				$('#table').show();
+				if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+					$('#temp').show();
+					$('#submit').show();
+				}
+				if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+					$('#lipVapSatTemp').show();
+					$('#submit').show();
+				}
+			}
+			if($('input:radio[name=lipVapSatVar]:checked').val() == "1"){
+				$('#table').show();
+				if($('input:radio[name=tableIncrement]:checked').val() == "0"){
+					$('#pres').show();
+					$('#submit').show();
+				}
+				if($('input:radio[name=tableIncrement]:checked').val() == "1"){
+					$('#lipVapSatPres').show();
+					$('#submit').show();
+				}
+			}
+		}
+	}
+	$(document).ready(function() {
+		resetViews();
+		$("input:radio").change(function () {
+			resetViews();
+		});
+	});
 </script>
 {% endblock %}
diff --git a/django_airavata/apps/workspace/yarn.lock b/django_airavata/apps/workspace/yarn.lock
index a3e1e2a..2d5c8b1 100644
--- a/django_airavata/apps/workspace/yarn.lock
+++ b/django_airavata/apps/workspace/yarn.lock
@@ -1122,6 +1122,11 @@
   resolved "https://registry.yarnpkg.com/@vue/web-component-wrapper/-/web-component-wrapper-1.2.0.tgz#bb0e46f1585a7e289b4ee6067dcc5a6ae62f1dd1"
   integrity sha512-Xn/+vdm9CjuC9p3Ae+lTClNutrVhsXpzxvoTXXtoys6kVRX9FkueSUAqSWAyZntmVLlR4DosBV4pH8y5Z/HbUw==
 
+"@vue/web-component-wrapper@^1.3.0":
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz#b6b40a7625429d2bd7c2281ddba601ed05dc7f1a"
+  integrity sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==
+
 "@webassemblyjs/ast@1.8.5":
   version "1.8.5"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"