UNPKG

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
"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