Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save acetousk/ce1e25d66c984aab065192e8f4d42666 to your computer and use it in GitHub Desktop.
Save acetousk/ce1e25d66c984aab065192e8f4d42666 to your computer and use it in GitHub Desktop.
Copied vue and ftl components to allow overriding default behavior
Subject: [PATCH] Copied vue and ftl components to allow overriding default behavior
---
Index: data/SimpleScreensSetupData.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/data/SimpleScreensSetupData.xml b/data/SimpleScreensSetupData.xml
--- a/data/SimpleScreensSetupData.xml (revision 787bf9cf17e52f20b4eb4e69a03d3212dae7c493)
+++ b/data/SimpleScreensSetupData.xml (date 1708058009445)
@@ -73,6 +73,7 @@
</#if>
]]></resourceValue>
</moqui.screen.ScreenThemeResource>
+ <moqui.screen.ScreenThemeResource screenThemeId="DEFAULT_QUASAR" sequenceNum="10" resourceTypeEnumId="STRT_SCRIPT_FOOTER" resourceValue="/ssstatic/lib/FancyDropDown.js"/>
<!-- /vapps (vuet) header plugins -->
<moqui.screen.ScreenThemeResource screenThemeId="DEFAULT" sequenceNum="130" resourceTypeEnumId="STRT_HEADER_NAVBAR_COMP"
Index: screen/SimpleScreens/Order/OrderDetail.xml
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/screen/SimpleScreens/Order/OrderDetail.xml b/screen/SimpleScreens/Order/OrderDetail.xml
--- a/screen/SimpleScreens/Order/OrderDetail.xml (revision 787bf9cf17e52f20b4eb4e69a03d3212dae7c493)
+++ b/screen/SimpleScreens/Order/OrderDetail.xml (date 1708117634979)
@@ -15,6 +15,9 @@
<screen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://moqui.org/xsd/xml-screen-3.xsd"
default-menu-title="Order Detail" default-menu-index="1">
+ <!-- this is a test, and example, of overriding the default FTL macro template to use for this screen -->
+ <macro-template type="qvt" location="component://SimpleScreens/template/screen-macro/CustomScreenMacros.qvt.ftl"/>
+
<parameter name="orderId" required="true"/>
<transition name="editParty"><default-response url="//${appRoot}/Party/EditParty"/></transition>
@@ -135,6 +138,12 @@
<transition name="removeOrderItemReservations"><service-call name="mantle.product.AssetServices.remove#OrderItemReservations"/>
<default-response url="."/></transition>
+ <transition name="createProduct"><service-call name="create#mantle.product.Product" out-map="product"/>
+ <actions>
+ <script>ec.web.sendJsonResponse(product)</script>
+ </actions>
+ <default-response type="none"/></transition>
+
<transition-include name="searchPartyList" location="component://SimpleScreens/template/party/PartyForms.xml"/>
<transition-include name="getProductList" location="component://SimpleScreens/template/product/ProductTransitions.xml"/>
<transition-include name="getProductPrice" location="component://SimpleScreens/template/product/ProductTransitions.xml"/>
@@ -1361,7 +1370,28 @@
</field>
<field name="productId">
<conditional-field condition="isProductItemType &amp;&amp; orderPartInfo.partEditable">
- <drop-down><dynamic-options transition="getProductList" server-search="true" min-length="0"/></drop-down>
+ <fancy-drop-down><no-option><container-dialog id="NewProductDialog" button-text="New Product">
+ <form-single name="NewProductForm" transition="createProduct">
+ <field name="orderId"><default-field><hidden/></default-field></field>
+ <field name="productName"><default-field><text-line/></default-field></field>
+ <field name="productTypeEnumId"><default-field title="Product Type">
+ <widget-template-include location="component://webroot/template/screen/BasicWidgetTemplates.xml#enumDropDown">
+ <set field="enumTypeId" value="ProductType"/></widget-template-include>
+ </default-field></field>
+ <field name="ownerPartyId"><default-field title="Owned By Org"><drop-down>
+ <option key="_NA_" text="N/A"/>
+ <entity-options key="${partyId}" text="PartyNameTemplate">
+ <entity-find entity-name="mantle.party.PartyDetailAndRole">
+ <econdition field-name="roleTypeId" value="OrgInternal"/>
+ <econdition field-name="disabled" value="N" or-null="true"/>
+ <order-by field-name="organizationName"/>
+ </entity-find>
+ </entity-options>
+ </drop-down></default-field></field>
+ <field name="submitButton"><default-field title="Create"><submit/></default-field></field>
+ </form-single>
+ </container-dialog>
+ </no-option><dynamic-options transition="getProductList" server-search="true" min-length="0"/></fancy-drop-down>
</conditional-field>
</field>
<field name="productLink" from="productId"><default-field title="">
Index: template/screen-macro/CustomScreenMacros.qvt.ftl
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/template/screen-macro/CustomScreenMacros.qvt.ftl b/template/screen-macro/CustomScreenMacros.qvt.ftl
new file mode 100644
--- /dev/null (date 1708060295978)
+++ b/template/screen-macro/CustomScreenMacros.qvt.ftl (date 1708060295978)
@@ -0,0 +1,82 @@
+<#--
+This software is in the public domain under CC0 1.0 Universal plus a Grant of Patent License.
+
+To the extent possible under law, the author(s) have dedicated all
+copyright and related and neighboring rights to this software to the
+public domain worldwide. This software is distributed without any
+warranty.
+
+You should have received a copy of the CC0 Public Domain Dedication
+along with this software (see the LICENSE.md file). If not, see
+<http://creativecommons.org/publicdomain/zero/1.0/>.
+-->
+
+<#include "runtime://template/screen-macro/DefaultScreenMacros.qvt.ftl"/>
+
+<#macro "no-option">
+ <#recurse/>
+</#macro>
+<#macro "fancy-drop-down">
+ <#assign ddSubFieldNode = .node?parent>
+ <#assign ddFieldNode = ddSubFieldNode?parent>
+ <#assign tlId><@fieldId .node/></#assign>
+ <#assign allowMultiple = ec.getResource().expandNoL10n(.node["@allow-multiple"]!, "") == "true">
+ <#assign allowEmpty = ec.getResource().expandNoL10n(.node["@allow-empty"]!, "") == "true">
+ <#assign isDynamicOptions = .node["dynamic-options"]?has_content>
+ <#assign name><@fieldName .node/></#assign>
+ <#assign namePlain = ddFieldNode["@name"]>
+ <#assign options = sri.getFieldOptions(.node)>
+ <#assign currentValue = sri.getFieldValuePlainString(ddFieldNode, "")>
+ <#if !currentValue?has_content && .node["@no-current-selected-key"]?has_content>
+ <#assign currentValue = ec.getResource().expandNoL10n(.node["@no-current-selected-key"], "")></#if>
+ <#if currentValue?starts_with("[")><#assign currentValue = currentValue?substring(1, currentValue?length - 1)?replace(" ", "")></#if>
+ <#assign currentValueList = (currentValue?split(","))!>
+ <#if currentValueList?has_content><#if allowMultiple><#assign currentValue=""><#else><#assign currentValue = currentValueList[0]></#if></#if>
+ <#if !allowMultiple && !allowEmpty && !currentValue?has_content && options?has_content><#assign currentValue = options.keySet()?first></#if>
+ <#-- for server-side dynamic options/etc if no currentValue get first in options and set in context so fields rendering after this have it available -->
+ <#if currentValue?has_content && !ec.context.get(namePlain)?has_content && _formMap?exists && !_formMap.get(namePlain)?has_content>
+ <#assign _void = _formMap.put(ddFieldNode["@name"], currentValue)!></#if>
+ <#assign currentDescription = (options.get(currentValue))!>
+ <#assign validationClasses = formInstance.getFieldValidationClasses(ddSubFieldNode)>
+ <#assign optionsHasCurrent = currentDescription?has_content>
+ <#if !optionsHasCurrent && .node["@current-description"]?has_content>
+ <#assign currentDescription = ec.getResource().expand(.node["@current-description"], "")></#if>
+ <#if isDynamicOptions>
+ <#assign doNode = .node["dynamic-options"][0]>
+ <#assign depNodeList = doNode["depends-on"]>
+ <#assign doUrlInfo = sri.makeUrlByType(doNode["@transition"], "transition", doNode, "false")>
+ <#assign doUrlParameterMap = doUrlInfo.getParameterMap()>
+ <#if currentValue?has_content && !currentDescription?has_content><#assign currentDescription><@widgetTextValue .node true/></#assign></#if>
+ </#if>
+ <#assign fieldLabel><@fieldTitle ddSubFieldNode/></#assign>
+ <fancy-drop-down name="${name}" id="${tlId}"<#if fieldLabel?has_content> label="${fieldLabel}"</#if><#if formDisabled!> disable</#if><#rt>
+ <#t> class="<#if isDynamicOptions>dynamic-options</#if><#if .node["@style"]?has_content> ${ec.getResource().expandNoL10n(.node["@style"], "")}</#if><#if validationClasses?has_content> ${validationClasses}</#if>"<#rt>
+ <#t><#if fieldsJsName?has_content> v-model="${fieldsJsName}.${name}" :fields="${fieldsJsName}"<#else><#if allowMultiple> :value="[<#list currentValueList as curVal><#if curVal?has_content>'${curVal}',</#if></#list>]"<#else> value="${currentValue!}"</#if></#if>
+ <#t><#if allowMultiple> :multiple="true"</#if><#if allowEmpty> :allow-empty="true"</#if><#if .node["@combo-box"]! == "true"> :combo="true"</#if>
+ <#t><#if .node["@required-manual-select"]! == "true"> :required-manual-select="true"</#if>
+ <#t><#if .node["@submit-on-select"]! == "true"> :submit-on-select="true"</#if>
+ <#t> :bg-color="formProps.fieldChanged('${name}')?'blue-1':''"
+ <#t><#if .node?parent["@tooltip"]?has_content> tooltip="${ec.getResource().expand(.node?parent["@tooltip"], "")}"</#if>
+ <#t><#if ownerForm?has_content> form="${ownerForm}"</#if><#if .node["@size"]?has_content> size="${.node["@size"]}"</#if>
+ <#if isDynamicOptions> options-url="${doUrlInfo.url}" value-field="${doNode["@value-field"]!"value"}" label-field="${doNode["@label-field"]!"label"}"<#if doNode["@depends-optional"]! == "true"> :depends-optional="true"</#if>
+ <#t> :depends-on="{<#list depNodeList as depNode><#local depNodeField = depNode["@field"]>'${depNode["@parameter"]!depNodeField}':'${depNodeField}'<#sep>, </#list>}"
+ <#t> :options-parameters="{<#list doUrlParameterMap.keySet() as parameterKey><#if doUrlParameterMap.get(parameterKey)?has_content>'${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(parameterKey)}':'${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(doUrlParameterMap.get(parameterKey))}', </#if></#list>}"
+ <#t><#if doNode["@server-search"]! == "true"> :server-search="true"</#if><#if doNode["@delay"]?has_content> :server-delay="${doNode["@delay"]}"</#if>
+ <#t><#if doNode["@min-length"]?has_content> :server-min-length="${doNode["@min-length"]}"</#if>
+ <#t><#if (.node?children?size > 1)> :options-load-init="true"</#if>
+ </#if>
+ :options="[<#if currentValue?has_content && !allowMultiple && !optionsHasCurrent>{value:'${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(currentValue)}',label:'<#if currentDescription?has_content>${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(currentDescription!)}<#else>${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(currentValue)}</#if>'},</#if><#rt>
+ <#t><#list (options.keySet())! as key>{value:'<#if key?has_content>${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(key)}</#if>',label:'${Static["org.moqui.util.WebUtilities"].encodeHtmlJsSafe(options.get(key)!)}'}<#sep>,</#list>]"
+ <#lt>>
+
+ <template v-slot:no-option><#visit .node["no-option"][0]/></template>
+ <#-- support <#if .node["@current"]! == "first-in-list"> again? -->
+ <#if ec.getResource().expandNoL10n(.node["@show-not"]!, "") == "true">
+ <template v-slot:after>
+ <q-field dense outlined :bg-color="formProps.fieldChanged('${name}_not')?'blue-1':''">
+ <#t><q-checkbox size="xs" name="${name}_not" label="${ec.getL10n().localize("Not")}"<#if ownerForm?has_content> form="${ownerForm}"</#if><#rt>
+ <#t><#if fieldsJsName?has_content> true-value="Y" false-value="N" v-model="${fieldsJsName}.${name}_not"<#else> value="Y"<#if ec.getWeb().parameters.get(name + "_not")! == "Y"> checked="checked"</#if></#if>></q-checkbox></q-field>
+ </template>
+ </#if>
+ </fancy-drop-down>
+</#macro>
Index: screen/ssstatic/lib/FancyDropDown.js
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/screen/ssstatic/lib/FancyDropDown.js b/screen/ssstatic/lib/FancyDropDown.js
new file mode 100644
--- /dev/null (date 1708064291106)
+++ b/screen/ssstatic/lib/FancyDropDown.js (date 1708064291106)
@@ -0,0 +1,287 @@
+Vue.component('fancy-drop-down', {
+ name: "fancyDropDown",
+ props: { value:[Array,String], options:{type:Array,'default':function(){return [];}}, combo:Boolean,
+ allowEmpty:Boolean, multiple:Boolean, requiredManualSelect:Boolean, submitOnSelect:Boolean,
+ optionsUrl:String, optionsParameters:Object, optionsLoadInit:Boolean,
+ serverSearch:Boolean, serverDelay:{type:Number,'default':300}, serverMinLength:{type:Number,'default':1},
+ labelField:{type:String,'default':'label'}, valueField:{type:String,'default':'value'},
+ dependsOn:Object, dependsOptional:Boolean, form:String, fields:{type:Object},
+ tooltip:String, label:String, name:String, id:String, disable:Boolean, bgColor:String, onSelectGoTo:String },
+ data: function() { return { curOptions:this.options, allOptions:this.options, lastVal:null, lastSearch:null, loading:false } },
+ template:
+ // was: ':fill-input="!multiple" hide-selected' changed to ':hide-selected="multiple"' to show selected to the left of input,
+ // fixes issues with fill-input where set values would sometimes not be displayed
+ '<q-select ref="qSelect" v-bind:value="value" v-on:input="handleInput($event)"' +
+ ' dense outlined options-dense use-input :hide-selected="multiple" :name="name" :id="id" :form="form"' +
+ ' input-debounce="500" @filter="filterFn" :clearable="allowEmpty||multiple" :disable="disable"' +
+ ' :multiple="multiple" :emit-value="!onSelectGoTo" map-options behavior="menu"' +
+ ' :rules="[val => allowEmpty||multiple||val===\'\'||(val&&val.length)||\'Please select an option\']"' +
+ ' stack-label :label="label" :loading="loading" :bg-color="bgColor" :options="curOptions">' +
+ '<q-tooltip v-if="tooltip">{{tooltip}}</q-tooltip>' +
+ '<template v-slot:no-option><slot name="no-option"><q-item><q-item-section class="text-grey">No results fancy!</q-item-section></q-item></slot></template>' +
+ '<template v-if="multiple" v-slot:prepend><div>' +
+ '<q-chip v-for="valueEntry in value" :key="valueEntry" dense size="md" class="q-my-xs" removable @remove="removeValue(valueEntry)">{{optionLabel(valueEntry)}}</q-chip>' +
+ '</div></template>' +
+ '<template v-slot:append><slot name="append"></slot></template>' +
+ '<template v-slot:after>' +
+ '<slot name="after"></slot>' +
+ '</template>' +
+ '</q-select>',
+ // TODO: how to add before slot pass through without the small left margin when nothing in the slot? <template v-slot:before><slot name="before"></slot></template>
+ methods: {
+ handleInput: function($event) {
+ // console.warn(this.onSelectGoTo + ": " + JSON.stringify($event));
+ if (this.onSelectGoTo && this.onSelectGoTo.length) {
+ if ($event[this.onSelectGoTo]) this.$root.setUrl($event[this.onSelectGoTo]);
+ } else {
+ this.$emit('input', $event);
+ }
+ if (this.submitOnSelect) {
+ var vm = this;
+ // this doesn't work, even alternative of custom-event with event handler in DefaultScreenMacros.qvt.ftl in the drop-down macro that explicitly calls the q-form submit() method: vm.$nextTick(function() { console.log("emitting submit"); vm.$emit('submit'); });
+ // doesn't work, q-form submit() method blows up without an even, in spite of what docs say: vm.$nextTick(function() { console.log("calling parent submit"); console.log(vm.$parent); vm.$parent.submit(); });
+ // doesn't work, q-form submit() doesn't like this event for whatever reason, method missing on it: vm.$nextTick(function() { console.log("calling parent submit with event"); console.log(vm.$parent); vm.$parent.submit($event); });
+
+ // TODO: find a better approach, perhaps pass down a reference to m-form or something so can refer to it more explicitly and handle Vue components in between
+ // TODO: if found a better approach change the removeValue method below
+ // this assumes the grandparent is m-form, if not it will blow up... alternatives are tricky
+ vm.$nextTick(function() { vm.$parent.$parent.submitForm(); });
+ }
+ },
+ filterFn: function(search, doneFn, abortFn) {
+ if (this.serverSearch) {
+ if ((this.lastSearch === search) || (this.serverMinLength && ((search ? search.length : 0) < this.serverMinLength))) {
+ doneFn();
+ } else {
+ this.lastSearch = search;
+ this.populateFromUrl({term:search}, doneFn, abortFn);
+ }
+ } else if (this.allOptions && this.allOptions.length) {
+ var vm = this;
+ if (search && search.length) {
+ doneFn(function() {
+ var needle = search.toLowerCase();
+ vm.curOptions = vm.allOptions.filter(function (v) {
+ return v.label && v.label.toLowerCase().indexOf(needle) > -1;
+ });
+ });
+ } else {
+ if ((vm.curOptions ? vm.curOptions.length : 0) === (vm.allOptions ? vm.allOptions.length : 0)) {
+ doneFn();
+ } else {
+ doneFn(function() { vm.curOptions = vm.allOptions; });
+ }
+ }
+ } else if (this.optionsUrl && this.optionsUrl.length) {
+ // no current options, get from server
+ this.populateFromUrl({}, doneFn, abortFn);
+ } else {
+ console.error("m-drop-down " + this.name + " has no options and no options-url");
+ abortFn();
+ }
+ },
+ processOptionList: function(list, page, term) {
+ var newData = [];
+ var labelField = this.labelField;
+ var valueField = this.valueField;
+ $.each(list, function(idx, curObj) {
+ var valueVal = curObj[valueField];
+ var labelVal = curObj[labelField];
+ newData.push(Object.assign(curObj, { value:valueVal||labelVal, label:labelVal||valueVal }));
+ });
+ return newData;
+ },
+ serverData: function(params) {
+ var hasAllParms = true;
+ var dependsOnMap = this.dependsOn;
+ var parmMap = this.optionsParameters;
+ var reqData = { moquiSessionToken: this.$root.moquiSessionToken };
+ for (var parmName in parmMap) { if (parmMap.hasOwnProperty(parmName)) reqData[parmName] = parmMap[parmName]; }
+ for (var doParm in dependsOnMap) { if (dependsOnMap.hasOwnProperty(doParm)) {
+ var doValue;
+ if (this.fields) {
+ doValue = this.fields[dependsOnMap[doParm]];
+ } else {
+ var doParmJqEl = $('#' + dependsOnMap[doParm]);
+ doValue = doParmJqEl.val();
+ if (!doValue) doValue = doParmJqEl.find('select').val();
+ }
+ // console.warn("do " + doParm + ":" + dependsOnMap[doParm] + " val " + doValue);
+ if (!doValue) { hasAllParms = false; } else { reqData[doParm] = doValue; }
+ }}
+ if (params) { reqData.term = params.term || ''; reqData.pageIndex = (params.page || 1) - 1; }
+ else if (this.serverSearch) { reqData.term = ''; reqData.pageIndex = 0; }
+ reqData.hasAllParms = hasAllParms;
+ return reqData;
+ },
+ processResponse: function(data, params) {
+ if (moqui.isArray(data)) {
+ return { results:this.processOptionList(data, null, params.term) };
+ } else {
+ params.page = params.page || 1; // NOTE: 1 based index, is 0 based on server side
+ var pageSize = data.pageSize || 20;
+ return { results: this.processOptionList(data.options, params.page, params.term),
+ pagination: { more: (data.count ? (params.page * pageSize) < data.count : false) } };
+ }
+ },
+ populateFromUrl: function(params, doneFn, abortFn) {
+ var reqData = this.serverData(params);
+ // console.log("populateFromUrl 1 " + this.optionsUrl + " reqData.hasAllParms " + reqData.hasAllParms + " dependsOptional " + this.dependsOptional);
+ // console.log(reqData);
+ if (!this.optionsUrl || !this.optionsUrl.length) {
+ console.warn("In m-drop-down tried to populateFromUrl but no optionsUrl");
+ if (abortFn) abortFn();
+ return;
+ }
+ if (!reqData.hasAllParms && !this.dependsOptional) {
+ console.warn("In m-drop-down tried to populateFromUrl but not hasAllParms and not dependsOptional");
+ this.curOptions = [];
+ this.allOptions = [];
+ if (abortFn) abortFn();
+ return;
+ }
+ var vm = this;
+ this.loading = true;
+ $.ajax({ type:"POST", url:this.optionsUrl, data:reqData, dataType:"json", headers:{Accept:'application/json'},
+ error:function(jqXHR, textStatus, errorThrown) {
+ vm.loading = false;
+ moqui.handleAjaxError(jqXHR, textStatus, errorThrown);
+ if (abortFn) abortFn();
+ },
+ success: function(data) {
+ vm.loading = false;
+ var list = moqui.isArray(data) ? data : data.options;
+ var procList = vm.processOptionList(list, null, (params ? params.term : null));
+ if (list) {
+ if (doneFn) {
+ doneFn(function() {
+ vm.setNewOptions(procList);
+ });
+ } else {
+ vm.setNewOptions(procList);
+ if (vm.$refs.qSelect) vm.$refs.qSelect.refresh();
+ // tried this for some drop-downs getting value set and have options but not showing current value's label, didn't work: if (vm.$refs.qSelect) vm.$nextTick(function() { vm.$refs.qSelect.refresh(); });
+ // NOTE: don't want to do this, was mistakenly used before, use only if setting the input value string to an explicit value otherwise clears it and calls filter again: vm.$refs.qSelect.updateInputValue();
+ }
+ }
+ }
+ });
+ },
+ setNewOptions: function(options) {
+ this.curOptions = options;
+ if (this.multiple && this.allOptions && this.allOptions.length && this.value && this.value.length && moqui.isArray(this.value)) {
+ // for multiple retain current value(s) in allOptions, at end of Array, so that in most cases already selected values are retained
+ var newAllOptions = options.slice();
+ for (var vi = 0; vi < this.value.length; vi++) {
+ var curValue = this.value[vi];
+ for (var oi = 0; oi < this.allOptions.length; oi++) {
+ var curOption = this.allOptions[oi];
+ if (curValue === curOption.value) newAllOptions.push(curOption);
+ }
+ }
+ this.allOptions = newAllOptions;
+ } else {
+ this.allOptions = options;
+ this.checkCurrentValue(this.allOptions);
+ }
+ },
+ checkCurrentValue: function(options) {
+ // if cur value not in new options either clear it or set it to the new first option in list if !allowEmpty
+ var isInNewOptions = false;
+ var valIsArray = moqui.isArray(this.value);
+ if (this.value && this.value.length && options) for (var i=0; i<options.length; i++) {
+ var curObj = options[i];
+ // console.warn("option val " + curObj.value + " cur value " + JSON.stringify(this.value) + " valIsArray " + valIsArray + " is in value " + (valIsArray ? this.value.includes(curObj.value) : curObj.value === this.value));
+ if (valIsArray ? this.value.includes(curObj.value) : curObj.value === this.value) {
+ isInNewOptions = true;
+ break;
+ }
+ }
+
+ // console.warn("curOptions updated " + this.name + " allowEmpty " + this.allowEmpty + " value '" + this.value + "' " + " isInNewOptions " + isInNewOptions + ": " + JSON.stringify(options));
+ if (!isInNewOptions) {
+ if (!this.allowEmpty && !this.multiple && options && options.length && options[0].value && (!this.requiredManualSelect || (!this.submitOnSelect && options.length === 1))) {
+ // simulate normal select behavior with no empty option (not allowEmpty) where first value is selected by default
+ // console.warn("checkCurrentValue setting " + this.name + " to " + options[0].value + " options " + options.length);
+ this.$emit('input', options[0].value);
+ } else {
+ // console.warn("setting " + this.name + " to null");
+ this.$emit('input', null);
+ }
+ }
+ },
+ optionLabel: function(value) {
+ var options = this.allOptions;
+ if (!options || !options.length) return "";
+ for (var i=0; i < options.length; i++) {
+ var curOption = options[i];
+ if (value === curOption.value) return curOption.label;
+ }
+ return "";
+ },
+ removeValue: function(value) {
+ var curValueArr = this.value;
+ if (!moqui.isArray(curValueArr)) { console.warn("Tried to remove value from m-drop-down multiple " + this.name + " but value is not an Array"); return; }
+ var newValueArr = [];
+ for (var i = 0; i < curValueArr.length; i++) {
+ var valueEntry = curValueArr[i];
+ if (valueEntry !== value) newValueArr.push(valueEntry);
+ }
+ if (curValueArr.length !== newValueArr.length) this.$emit('input', newValueArr);
+ // copied from handleInput method above
+ if (this.submitOnSelect) {
+ var vm = this;
+ // this doesn't work, even alternative of custom-event with event handler in DefaultScreenMacros.qvt.ftl in the drop-down macro that explicitly calls the q-form submit() method: vm.$nextTick(function() { console.log("emitting submit"); vm.$emit('submit'); });
+ // doesn't work, q-form submit() method blows up without an even, in spite of what docs say: vm.$nextTick(function() { console.log("calling parent submit"); console.log(vm.$parent); vm.$parent.submit(); });
+ // doesn't work, q-form submit() doesn't like this event for whatever reason, method missing on it: vm.$nextTick(function() { console.log("calling parent submit with event"); console.log(vm.$parent); vm.$parent.submit($event); });
+
+ // TODO: find a better approach, perhaps pass down a reference to m-form or something so can refer to it more explicitly and handle Vue components in between
+ // TODO: if found a better approach change the handleInput method above
+ // this assumes the grandparent is m-form, if not it will blow up... alternatives are tricky
+ vm.$nextTick(function() { vm.$parent.$parent.submitForm(); });
+ }
+ },
+ clearAll: function() { this.$emit('input', null); }
+ },
+ mounted: function() {
+ // TODO: handle combo somehow: if (this.combo) { opts.tags = true; opts.tokenSeparators = [',',' ']; }
+
+ if (this.serverSearch) {
+ if (!this.optionsUrl) console.error("m-drop-down in form " + this.form + " has no options-url but has server-search=true");
+ }
+ if (this.optionsUrl && this.optionsUrl.length) {
+ var dependsOnMap = this.dependsOn;
+ for (var doParm in dependsOnMap) { if (dependsOnMap.hasOwnProperty(doParm)) {
+ if (this.fields) {
+ var vm = this;
+ this.$watch('fields.' + dependsOnMap[doParm], function() {
+ // in the case of dependency change clear current value
+ vm.$emit('input', null);
+ vm.populateFromUrl({term:vm.lastSearch});
+ });
+ } else {
+ // TODO: if no fields passed, use some sort of DOM-based value like jQuery val()?
+ }
+ } }
+ // do initial populate if not a serverSearch or for serverSearch if we have an initial value do the search so we don't display the ID
+ if (this.optionsLoadInit) {
+ if (!this.serverSearch) { this.populateFromUrl(); }
+ else if (this.value && this.value.length && moqui.isString(this.value)) { this.populateFromUrl({term:this.value}); }
+ }
+ }
+ // simulate normal select behavior with no empty option (not allowEmpty) where first value is selected by default - but only do for 1 option to force user to think and choose from multiple
+ if (!this.multiple && !this.allowEmpty && (!this.value || !this.value.length) && this.options && this.options.length && (!this.requiredManualSelect || (!this.submitOnSelect && options.length === 1))) {
+ this.$emit('input', this.options[0].value);
+ }
+ }
+ /* probably don't need, remove sometime:
+ watch: {
+ // need to watch for change to options prop? options: function(options) { this.curOptions = options; },
+ curOptionsFoo: function(options) {
+ // save the lastVal if there is one to remember what was selected even if new options don't have it, just in case options change again
+ if (this.value && this.value.length) this.lastVal = this.value;
+
+ }
+ }
+ */
+});
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment