UNPKG

contacts-pane

Version:

Contacts Pane: Contacts manager for Address Book, Groups, and Individuals.

239 lines 11.4 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.renderAutoComplete = renderAutoComplete; const solid_logic_1 = require("solid-logic"); const solid_ui_1 = require("solid-ui"); const publicData_1 = require("./publicData"); const AUTOCOMPLETE_THRESHOLD = 4; // don't check until this many characters typed const AUTOCOMPLETE_ROWS = 20; // 20? const AUTOCOMPLETE_ROWS_STRETCH = 40; const AUTOCOMPLETE_DEBOUNCE_MS = 300; const autocompleteRowStyle = 'border: 0.2em solid straw;'; // @@ white // The core of the autocomplete UI function renderAutoComplete(dom, options, // subject:NamedNode, predicate:NamedNode, callback) { return __awaiter(this, void 0, void 0, function* () { function complain(message) { const errorRow = table.appendChild(dom.createElement('tr')); console.log(message); errorRow.appendChild(solid_ui_1.widgets.errorMessageBlock(dom, message, 'pink')); solid_ui_1.style.setStyle(errorRow, 'autocompleteRowStyle'); errorRow.style.padding = '1em'; } function remove(ele) { if (ele) { ele.parentNode.removeChild(ele); } } function finish(object, name) { console.log('Auto complete: finish! ' + object); // remove(options.cancelButton) // remove(options.acceptButton) // remove(div) callback(object, name); } function gotIt(object, name) { return __awaiter(this, void 0, void 0, function* () { if (options.acceptButton) { options.acceptButton.disabled = false; searchInput.value = name; // complete it foundName = name; foundObject = object; console.log('Auto complete: name: ' + name); console.log('Auto complete: waiting for accept ' + object); return; } finish(object, name); }); } function acceptButtonHandler(_event) { return __awaiter(this, void 0, void 0, function* () { if (searchInput.value === foundName) { // still finish(foundObject, foundName); } else { options.acceptButton.disabled = true; } }); } function cancelButtonHandler(_event) { return __awaiter(this, void 0, void 0, function* () { console.log('Auto complete: Canceled by user! '); div.innerHTML = ''; // Clear out the table }); } function nameMatch(filter, candidate) { const parts = filter.split(' '); // Each name part must be somewhere for (let j = 0; j < parts.length; j++) { const word = parts[j]; if (candidate.toLowerCase().indexOf(word) < 0) return false; } return true; } function cancelText(_event) { searchInput.value = ''; if (options.acceptButton) { options.acceptButton.disabled == true; // start again } candidatesLoaded = false; } function thinOut(filter) { var hits = 0; var pick = null, pickedName = ''; for (let j = table.children.length - 1; j > 0; j--) { // backwards as we are removing rows let row = table.children[j]; if (nameMatch(filter, row.textContent)) { hits += 1; pick = row.getAttribute('subject'); pickedName = row.textContent; row.style.display = ''; row.style.color = 'blue'; // @@ chose color } else { ; row.style.display = 'none'; } } if (hits == 1) { // Maybe require green confirmation button be clicked? console.log(` auto complete elimination: "${filter}" -> "${pickedName}"`); gotIt(solid_logic_1.store.sym(pick), pickedName); // uri, name } } function clearList() { while (table.children.length > 1) { table.removeChild(table.lastChild); } } function inputEventHHandler(_event) { return __awaiter(this, void 0, void 0, function* () { if (runningTimeout) { clearTimeout(runningTimeout); } setTimeout(refreshList, AUTOCOMPLETE_DEBOUNCE_MS); }); } function refreshList() { return __awaiter(this, void 0, void 0, function* () { if (inputEventHandlerLock) { console.log(`Ignoring "${searchInput.value}" because of lock `); return; } inputEventHandlerLock = true; var languagePrefs = yield (0, publicData_1.getPreferredLanguages)(); const filter = searchInput.value.trim().toLowerCase(); if (filter.length < AUTOCOMPLETE_THRESHOLD) { // too small clearList(); candidatesLoaded = false; numberOfRows = AUTOCOMPLETE_ROWS; } else { if (allDisplayed && lastFilter && filter.startsWith(lastFilter)) { thinOut(filter); // reversible? inputEventHandlerLock = false; return; } var bindings; try { bindings = yield (0, publicData_1.queryPublicDataByName)(filter, OrgClass, options.queryParams); // bindings = await queryDbpedia(sparql) } catch (err) { complain('Error querying db of organizations: ' + err); inputEventHandlerLock = false; return; } candidatesLoaded = true; const loadedEnough = bindings.length < publicData_1.AUTOCOMPLETE_LIMIT; if (loadedEnough) { lastFilter = filter; } else { lastFilter = null; } clearList(); const slimmed = (0, publicData_1.filterByLanguage)(bindings, languagePrefs); if (loadedEnough && slimmed.length <= AUTOCOMPLETE_ROWS_STRETCH) { numberOfRows = slimmed.length; // stretch if it means we get all items } allDisplayed = loadedEnough && slimmed.length <= numberOfRows; console.log(` Filter:"${filter}" bindings: ${bindings.length}, slimmed to ${slimmed.length}; rows: ${numberOfRows}, Enough? ${loadedEnough}, All displayed? ${allDisplayed}`); slimmed.slice(0, numberOfRows).forEach(binding => { const row = table.appendChild(dom.createElement('tr')); solid_ui_1.style.setStyle(row, 'autocompleteRowStyle'); var uri = binding.subject.value; var name = binding.name.value; row.setAttribute('style', 'padding: 0.3em;'); row.setAttribute('subject', uri); row.style.color = allDisplayed ? '#080' : '#000'; // green means 'you should find it here' row.textContent = name; row.addEventListener('click', (_event) => __awaiter(this, void 0, void 0, function* () { console.log(' click row textContent: ' + row.textContent); console.log(' click name: ' + name); gotIt(solid_logic_1.store.sym(uri), name); })); }); } inputEventHandlerLock = false; }); } // refreshList /* sparqlForSearch * * name -- e.g., "mass" * theType -- e.g., <http://umbel.org/umbel/rc/EducationalOrganization> */ function sparqlForSearch(name, theType) { let clean = name.replace(/\W/g, ''); // Remove non alphanum so as to protect regexp const sparql = `select distinct ?subject, ?name where { ?subject a <${theType.uri}>; rdfs:label ?name FILTER regex(?name, "${clean}", "i") } LIMIT ${publicData_1.AUTOCOMPLETE_LIMIT}`; return sparql; } const queryParams = options.queryParams; const OrgClass = options.class; // kb.sym('http://umbel.org/umbel/rc/EducationalOrganization') // @@@ other if (options.acceptButton) { options.acceptButton.addEventListener('click', acceptButtonHandler, false); } if (options.cancelButton) { // options.cancelButton.addEventListener('click', cancelButtonHandler, false) } let candidatesLoaded = false; let runningTimeout = null; let inputEventHandlerLock = false; let allDisplayed = false; var lastFilter = null; var numberOfRows = AUTOCOMPLETE_ROWS; var div = dom.createElement('div'); var foundName = null; // once found accepted string must match this var foundObject = null; var table = div.appendChild(dom.createElement('table')); table.setAttribute('style', 'max-width: 30em; margin: 0.5em;'); const head = table.appendChild(dom.createElement('tr')); solid_ui_1.style.setStyle(head, 'autocompleteRowStyle'); const cell = head.appendChild(dom.createElement('td')); const searchInput = cell.appendChild(dom.createElement('input')); searchInput.setAttribute('type', 'text'); const searchInputStyle = solid_ui_1.style.searchInputStyle || 'border: 0.1em solid #444; border-radius: 0.5em; width: 100%; font-size: 100%; padding: 0.1em 0.6em'; // @ searchInput.setAttribute('style', searchInputStyle); searchInput.addEventListener('keyup', function (event) { if (event.keyCode === 13) { acceptButtonHandler(event); } }, false); searchInput.addEventListener('input', inputEventHHandler); return div; }); } // renderAutoComplete const ends = 'ENDS'; //# sourceMappingURL=autocompletePicker.js.map