UNPKG

@teipublisher/pb-components

Version:
161 lines (148 loc) 4.72 kB
import '@lrnwebcomponents/es-global-bridge'; import { Registry } from './registry.js'; import { resolveURL } from '../utils.js'; function expandTemplate(template = '', options) { return template.replace(/\${([^}]+)}/g, (match, p) => { let replacement; if (options[p]) { replacement = options[p]; } return replacement || ''; }); } function getTemplate(configElem, selector) { const template = configElem.querySelector(selector); if (template instanceof HTMLTemplateElement) { const wrapper = document.createElement('div'); wrapper.appendChild(template.content.cloneNode(true)); return wrapper.innerHTML; } return ''; } export class Airtable extends Registry { constructor(configElem) { super(configElem); this.apiKey = configElem.getAttribute('api-key'); this.baseKey = configElem.getAttribute('base'); this.table = configElem.getAttribute('table'); this.view = configElem.getAttribute('view'); this.filterExpr = configElem.getAttribute('filter'); this.labelExpr = configElem.getAttribute('label'); const fieldsDef = configElem.getAttribute('fields'); if (fieldsDef) { this.fields = fieldsDef.split(/\s*,\s*/); } else { this.fields = ['ID']; } const tokenizeDef = configElem.getAttribute('tokenize'); if (tokenizeDef) { this.tokenize = tokenizeDef.split(/\s*,\s*/); } else { this.tokenize = [this.fields[0]]; } this.tokenizeChars = configElem.getAttribute('tokenize-regex') || "\\W"; this.infoExpr = getTemplate(configElem, '.info'); this.detailExpr = getTemplate(configElem, '.detail'); this._init(); } _init() { window.ESGlobalBridge.requestAvailability(); const path = resolveURL('../lib/airtable.browser.js'); window.ESGlobalBridge.instance.load('airtable', path); window.addEventListener( 'es-bridge-airtable-loaded', this._initAirtable.bind(this), { once: true }, ); } _initAirtable() { const Airtable = require('airtable'); this.base = new Airtable({ apiKey: this.apiKey }).base(this.baseKey); } async query(key) { key = key.toLowerCase(); const results = []; const filter = this.filterExpr ? expandTemplate(this.filterExpr, { key }) : null; const options = { fields: this.fields, // Selecting the first 3 records in Grid view: maxRecords: 100 }; if (this.view) { options.view = this.view; } if (filter) { options.filterByFormula = filter; } return new Promise((resolve, reject) => { this.base(this.table) .select(options) .firstPage((err, records) => { if (err) { console.error(err); reject(err); return; } records.forEach(record => { const data = {}; this.fields.forEach((field) => { data[field] = record.get(field); }); const result = { register: this._register, id: record.id, label: expandTemplate(this.labelExpr, data), details: expandTemplate(this.detailExpr, data), provider: 'airtable' }; results.push(result); }); resolve({ totalItems: 3, items: results, }); }); }); } info(key, container) { return new Promise((resolve, reject) => { this.base(this.table).find(key, (err, record) => { if (err) { switch (err.statusCode) { case 404: reject(`No record found for ${key} in table ${this.table}`); break; default: reject(`${err.statusCode}: ${err.message}`); break; } return; } if (Object.keys(record.fields).length === 0) { reject(`No record found for ${key} in table ${this.table}`); return; } let strings = []; const data = {}; this.fields.forEach((field) => { const value = record.get(field); if (value) { data[field] = value; strings.push(value); } }); const regex = new RegExp(this.tokenizeChars); this.tokenize.forEach((key) => { if (data[key]) { strings = strings.concat(data[key].split(regex)); } }); strings = strings.filter(tok => !/^\d+$/.test(tok)); strings.sort((s1, s2) => s2.length - s1.length); container.innerHTML = expandTemplate(this.infoExpr, data); resolve({ id: record.id, strings }); }); }); } }