dynamicsmobile
Version:
Allows development of off-line mobile and web business apps over the Dynamics Mobile platform. More info on https://www.dynamicsmobile.com
217 lines • 9.29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const updating_element_js_1 = require("lit-element/lib/updating-element.js");
const jquery_1 = tslib_1.__importDefault(require("jquery"));
const dms_control_datasource_1 = require("./dms-control-datasource");
class RefCombobox extends updating_element_js_1.UpdatingElement {
static get properties() {
return {
name: {
type: String,
// TODO: maybe reflect name/value to a hidden input for better general use
// but not really needed for the way it is used with knockout value binding now
},
value: {
type: String,
},
disabled: {
type: Boolean,
},
readonly: {
type: Boolean,
},
prefetch: {
type: Number,
},
appCode: {
type: String,
attribute: 'data-dms-appcode',
},
entity: {
type: String,
attribute: 'data-dms-entity',
},
display: {
type: String,
attribute: 'data-dms-display',
},
filter: {
type: String,
attribute: 'data-dms-filter',
},
};
}
static DOMReady() {
this._domready = this._domready || new Promise((resolve) => (0, jquery_1.default)(resolve));
return this._domready;
}
static fetchData(appcode, entity, filter, order, limit) {
return tslib_1.__awaiter(this, void 0, void 0, function* () {
// Wrapper method around $dms.core.data API, to add caching.
// TODO: This job should probably be left up to the browser and HTTP caching,
// or as part of the $dms API (or the <dms-control-datasource> to be scoped per view)
// TODO: Change to use getEntity2 or $dms.core.query and fetch just needed fields.
// Currently gets all fields, but only really needs DMS_ROWID and the refDisplayField
// (this.display in instances, will have to be added as argument and to the cache key)
// We also need to make sure jQuery domready event has fired,
// as the api base URL is not initialized before that.
yield this.DOMReady();
const cacheTTL = 2 * 60 * 1000;
const key = JSON.stringify([appcode, entity, filter, order, limit]);
if (!this.dataCache)
this.dataCache = {};
let promise = this.dataCache[key];
if (!promise || promise.TTL < Date.now()) {
promise = this.dataCache[key] = dms_control_datasource_1.DmsDataSourceControl.prototype.rawExecuteSelect({ appCode: appcode, entityName: entity, filter, sort: order, expand: [] });
promise.TTL = Date.now() + cacheTTL;
setTimeout(() => {
for (const key in this.dataCache) {
const promise = this.dataCache[key];
if (promise && promise.TTL < Date.now()) {
delete this.dataCache[key];
}
}
}, cacheTTL + 1000);
}
return yield promise;
});
}
constructor() {
super();
this.prefetch = 250;
this.usePrefetch = true;
}
update(props) {
super.update(props);
if (props.has('disabled')) {
if (this._cb) {
if (this.disabled)
this._cb.disable();
else
this._cb.enable();
}
}
if (['prefetch', 'appCode', 'entity', 'display', 'filter'].some(x => props.has(x))) {
this.usePrefetch = true;
return this.refresh();
}
if (props.has('value')) {
if (!this.value)
this.text = '';
if (this.value && this._cb && this._cb.vmap) {
this.text = this._cb.vmap[this.value];
if (!this.text && !this.usePrefetch) {
return this.refresh();
}
}
if (this._cb) {
this._cb.$element.val(this.text);
this._cb.selected = !!this.text;
this._cb.$container.toggleClass('combobox-selected', this._cb.selected);
// Without the following line the combobox gets cleared on the first blur
// but I don't understand why... there is nothing in the blur handler looking at $target.
this._cb.$target.val(this.value);
}
}
}
refresh() {
const cb = this._cb;
if (!cb)
return;
if (this.prefetch && this.usePrefetch) {
cb.process = cb.original_process;
cb.refresh().then(() => {
if (cb.options.items >= this.prefetch) {
this.usePrefetch = false;
this.refresh();
}
}).catch(console.error);
}
else {
const debounceTimeout = 300;
let timer = null;
cb.process = () => {
if (timer)
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
cb.refresh(true)
.then(() => cb.original_process(cb.source))
.catch(console.error);
}, debounceTimeout);
};
cb.refresh(false, this.value, 1).catch(console.error);
}
}
firstUpdated(props) {
super.firstUpdated(props);
const shadow = this.attachShadow({ mode: 'closed' });
document.querySelectorAll('style,link[rel=stylesheet]').forEach(node => shadow.appendChild(node.cloneNode(true)));
const cb = this._cb = (0, jquery_1.default)('<select></select>').appendTo(shadow).val('').combobox().data('combobox');
const h = (0, jquery_1.default)('<input hidden/>').insertAfter(this);
// if ($(this).attr('data-parsley-required') && Parsley) {
// // We want to set 'field:validated' event on the field,
// // but Parsley uses its own event system instead of jQuery's
// // and we have to wait for the field's Parsley instance to be
// // created first, so we will use a temporary 'field:init' handler.
// Parsley.on('field:init', function handleInit(instance, ...args) {
// if (h.is(instance.$element)) {
// instance.on('field:validated', function() {
// cb.$element.toggleClass('parsley-error', h.hasClass('parsley-error'));
// });
// Parsley.off('field:init', handleInit);
// }
// });
// h.attr('data-parsley-required', $(this).attr('data-parsley-required'));
// }
if (this.disabled) {
cb.disable();
}
const syncValue = (e) => {
if (this.value != cb.$target.val()) {
this.value = cb.$target.val();
this.text = cb.$element.val();
h.val(this.value);
// trigger parsley revalidate
h.get(0).dispatchEvent(new Event('input'));
this.dispatchEvent(new Event('change'));
}
};
cb.$source.change(syncValue);
cb.$element.blur(syncValue);
cb.refresh = (typing = false, id = null, limit = typing ? 20 : this.prefetch) => tslib_1.__awaiter(this, void 0, void 0, function* () {
const filter = [];
let filterAsStr = '';
if (this.filter)
filter.push(`(${this.filter})`);
if (typing && cb.query)
filter.push(`contains(${this.display}, '${cb.query}')`);
if (id)
filter.push(`DMS_ROWID eq '${id}'`);
filterAsStr = filter.join(' and ');
const records = yield this.constructor.fetchData(this.appCode, this.entity, filterAsStr, this.display, limit);
const map = {}, vmap = {};
records.forEach(r => map[r[this.display]] = r['DMS_ROWID']);
records.forEach(r => vmap[r['DMS_ROWID']] = r[this.display]);
const display = cb.source = Object.keys(map);
cb.map = map;
cb.vmap = vmap;
cb.options.items = display.length;
this.text = cb.vmap[this.value];
if (!typing) {
cb.selected = !!this.text;
cb.$container.toggleClass('combobox-selected', cb.selected);
cb.$element.val(this.text);
cb.$target.val(this.value);
}
});
// eslint-disable-next-line @typescript-eslint/camelcase
cb.original_process = cb.process;
return this.refresh();
}
}
exports.default = RefCombobox;
// if(window.customElements)
// customElements.define('dms-control-ref-combobox', RefCombobox);
//# sourceMappingURL=dms-control-lookup.js.map