Browse Source

feat: add onRecordRead datasource

ci/dependabot
danstarns 2 years ago
parent
commit
ea3ec6a223
  1. 41
      src/data_sources/index.ts
  2. 1
      src/data_sources/model/DataRecords.ts
  3. 8
      src/data_sources/model/DataSource.ts
  4. 8
      src/data_sources/model/StyleDataVariable.ts
  5. 8
      src/dom_components/model/ComponentDataVariable.ts
  6. 14
      src/dom_components/view/ComponentDataVariableView.ts
  7. 13
      src/domain_abstract/model/StyleableModel.ts
  8. 38
      test/specs/data_sources/index.ts

41
src/data_sources/index.ts

@ -1,8 +1,6 @@
import { ItemManagerModule, ModuleConfig } from '../abstract/Module';
import { AddOptions, ObjectAny, RemoveOptions } from '../common';
import { AddOptions, RemoveOptions } from '../common';
import EditorModel from '../editor/model/Editor';
import { get, stringToPath } from '../utils/mixins';
import DataRecord from './model/DataRecord';
import DataSource from './model/DataSource';
import DataSources from './model/DataSources';
import { DataSourceProps, DataSourcesEvents } from './types';
@ -58,41 +56,4 @@ export default class DataSourceManager extends ItemManagerModule<ModuleConfig, D
remove(id: string | DataSource, opts?: RemoveOptions) {
return this.__remove(id, opts);
}
/**
* Get value from data sources by key
* @param {String} key Path to value.
* @param {any} defValue
* @returns {any}
* const value = dsm.getValue('ds_id.record_id.propName', 'defaultValue');
*/
getValue(key: string | string[], defValue: any) {
return get(this.getContext(), key, defValue);
}
getContext() {
return this.all.reduce((acc, ds) => {
acc[ds.id] = ds.records.reduce((accR, dr, i) => {
accR[i] = dr.attributes;
accR[dr.id || i] = dr.attributes;
return accR;
}, {} as ObjectAny);
return acc;
}, {} as ObjectAny);
}
fromPath(path: string) {
const result: [DataSource?, DataRecord?, string?] = [];
const [dsId, drId, ...resPath] = stringToPath(path || '');
const dataSource = this.get(dsId);
const dataRecord = dataSource?.records.get(drId);
dataSource && result.push(dataSource);
if (dataRecord) {
result.push(dataRecord);
resPath.length && result.push(resPath.join('.'));
}
return result;
}
}

1
src/data_sources/model/DataRecords.ts

@ -1,3 +1,4 @@
import { Model } from 'backbone';
import { AddOptions, Collection } from '../../common';
import { DataRecordProps } from '../types';
import DataRecord from './DataRecord';

8
src/data_sources/model/DataSource.ts

@ -51,7 +51,13 @@ export default class DataSource extends Model<DataSourceProps> {
}
getRecord(id: string | number): DataRecord | undefined {
return this.records.get(id);
const onRecordRead = this.transformers.onRecordRead;
const record = this.records.get(id);
if (record && onRecordRead) {
return onRecordRead({ record });
}
return record;
}
getRecords() {

8
src/data_sources/model/StyleDataVariable.ts

@ -30,9 +30,13 @@ export default class StyleDataVariable extends Model {
}
}
onDataSourceChange(model: any) {
onDataSourceChange() {
const { path } = this.attributes;
const newValue = get(model, stringToPath(path).join('.'), '');
const [dsId, drId, key] = stringToPath(path);
const ds = this?.em?.DataSources.get(dsId);
const dr = ds && ds.getRecord(drId);
const newValue = dr?.get(key);
this.set({ value: newValue });
}
}

8
src/dom_components/model/ComponentDataVariable.ts

@ -1,4 +1,4 @@
import { toLowerCase } from '../../utils/mixins';
import { stringToPath, toLowerCase } from '../../utils/mixins';
import Component from './Component';
import { ToHTMLOptions } from './types';
@ -17,7 +17,11 @@ export default class ComponentDataVariable extends Component {
getInnerHTML(opts: ToHTMLOptions & { keepVariables?: boolean } = {}) {
const { path, value } = this.attributes;
return opts.keepVariables ? path : this.em.DataSources.getValue(path, value);
const [dsId, drId, key] = stringToPath(path);
const ds = this.em.DataSources.get(dsId);
const dr = ds && ds.getRecord(drId);
return opts.keepVariables ? path : dr ? dr.get(key) : value;
}
static isComponent(el: HTMLElement) {

14
src/dom_components/view/ComponentDataVariableView.ts

@ -16,8 +16,11 @@ export default class ComponentDataVariableView extends ComponentView<ComponentDa
const { model, em } = this;
const { path } = model.attributes;
const normPath = stringToPath(path || '').join('.');
const [dsId, drId] = stringToPath(path || '');
const { DataSources } = em;
const [ds, dr] = DataSources.fromPath(path);
const ds = DataSources.get(dsId);
const dr = ds && ds.getRecord(drId);
const dataListeners: DataVariableListener[] = [];
const prevListeners = this.dataListeners || [];
@ -38,7 +41,14 @@ export default class ComponentDataVariableView extends ComponentView<ComponentDa
postRender() {
const { model, el, em } = this;
const { path, value } = model.attributes;
el.innerHTML = em.DataSources.getValue(path, value);
const { DataSources } = em;
const [dsId, drId, key, ...resPath] = stringToPath(path || '');
const ds = DataSources.get(dsId);
const dr = ds && ds.getRecord(drId);
el.innerHTML = dr ? dr.get(key) : value;
super.postRender();
}
}

13
src/domain_abstract/model/StyleableModel.ts

@ -147,7 +147,11 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
dataListeners.forEach(ls =>
this.listenTo(ls.obj, ls.event, () => {
const newValue = em?.DataSources.getValue(normPath, dataVar.get('value'));
const [dsId, drId, keyPath] = stringToPath(path);
const ds = em?.DataSources.get(dsId);
const dr = ds && ds.records.get(drId);
const newValue = dr && dr.get(keyPath);
this.updateStyleProp(styleProp, newValue);
})
);
@ -165,8 +169,13 @@ export default class StyleableModel<T extends ObjectHash = any> extends Model<T>
const resolvedStyle = { ...style };
keys(resolvedStyle).forEach(key => {
const styleValue = resolvedStyle[key];
if (styleValue instanceof StyleDataVariable) {
const resolvedValue = this.em?.DataSources.getValue(styleValue.get('path'), styleValue.get('value'));
const [dsId, drId, keyPath] = stringToPath(styleValue.get('path'));
const ds = this.em?.DataSources.get(dsId);
const dr = ds && ds.records.get(drId);
const resolvedValue = dr && dr.get(keyPath);
resolvedStyle[key] = resolvedValue || styleValue.get('value');
}
});

38
test/specs/data_sources/index.ts

@ -126,7 +126,7 @@ describe('DataSourceManager', () => {
});
});
describe.only('Transformers', () => {
describe('Transformers', () => {
let fixtures: HTMLElement;
let cmpRoot: ComponentWrapper;
@ -225,6 +225,42 @@ describe('DataSourceManager', () => {
const result = ds.getRecord('id1')?.get('content');
expect(result).toBe('I LOVE GRAPES');
});
test('onRecordRead', () => {
const testDataSource: DataSourceProps = {
id: 'test-data-source',
records: [],
transformers: {
onRecordRead: ({ record }) => {
const content = record.get('content');
return record.set('content', content.toUpperCase(), { avoidTransformers: true });
},
},
};
dsm.add(testDataSource);
const cmp = cmpRoot.append({
tagName: 'h1',
type: 'text',
components: [
{
type: 'data-variable',
value: 'default',
path: 'test-data-source.id1.content',
},
],
})[0];
const ds = dsm.get('test-data-source');
ds.addRecord({ id: 'id1', content: 'i love grapes' });
const el = cmp.getEl();
expect(el?.innerHTML).toContain('I LOVE GRAPES');
const result = ds.getRecord('id1')?.get('content');
expect(result).toBe('I LOVE GRAPES');
});
});
test('add DataSource with records', () => {

Loading…
Cancel
Save