UNPKG

@obliczeniowo/elementary

Version:
1 lines 192 kB
{"version":3,"file":"obliczeniowo-elementary-modeller.mjs","sources":["../../../../projects/components/modeller/components/modeller-box/modeller-box.component.ts","../../../../projects/components/modeller/components/modeller-box/modeller-box.component.html","../../../../projects/components/modeller/components/connector-item/connector-item.component.ts","../../../../projects/components/modeller/components/connector-item/connector-item.component.html","../../../../projects/components/modeller/components/integer-filter-connector/integer-filter-connector.component.ts","../../../../projects/components/modeller/components/integer-filter-connector/integer-filter-connector.component.html","../../../../projects/components/modeller/components/convert-to-histogram/convert-to-histogram.component.ts","../../../../projects/components/modeller/components/convert-to-histogram/convert-to-histogram.component.html","../../../../projects/components/modeller/components/range-filter/range-filter.component.ts","../../../../projects/components/modeller/components/range-filter/range-filter.component.html","../../../../projects/components/modeller/components/string-converter/string-converter.component.ts","../../../../projects/components/modeller/components/string-converter/string-converter.component.html","../../../../projects/components/modeller/components/split-box/split-box.component.ts","../../../../projects/components/modeller/components/value-input/value-input.component.ts","../../../../projects/components/modeller/components/value-input/value-input.component.html","../../../../projects/components/modeller/components/math-box/math-box.component.ts","../../../../projects/components/modeller/components/math-operator/math-operator.component.ts","../../../../projects/components/modeller/components/math-operator/math-operator.component.html","../../../../projects/components/modeller/components/const-or-value/const-or-value.component.ts","../../../../projects/components/modeller/components/const-or-value/const-or-value.component.html","../../../../projects/components/modeller/components/join-array-to-object-box/join-array-to-object-box.component.ts","../../../../projects/components/modeller/components/split-input-box/split-input-box.component.ts","../../../../projects/components/modeller/components/generate/generate.component.ts","../../../../projects/components/modeller/components/generate/generate.component.html","../../../../projects/components/modeller/components/concat-array-box/concat-array-box.component.ts","../../../../projects/components/modeller/components/formula-box/formula-box.component.ts","../../../../projects/components/modeller/components/formula/formula.component.ts","../../../../projects/components/modeller/components/formula/formula.component.html","../../../../projects/components/modeller/get-request/get-request.component.ts","../../../../projects/components/modeller/get-request/get-request.component.html","../../../../projects/components/modeller/services/modeller.service.ts","../../../../projects/components/modeller/components/modeller-space/modeller-space.component.ts","../../../../projects/components/modeller/components/modeller-space/modeller-space.component.html","../../../../projects/components/modeller/modeller.module.ts","../../../../projects/components/modeller/obliczeniowo-elementary-modeller.ts"],"sourcesContent":["import { Component, ComponentRef, HostBinding, Input, Output, SimpleChanges, ViewChild, ViewContainerRef, ElementRef, ChangeDetectorRef } from '@angular/core';\n\nimport { Point2D } from '@obliczeniowo/elementary/classes';\n\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\nimport { keys } from '@obliczeniowo/elementary/objects';\n\nimport { BoxModel } from '../../models/box.model';\nimport { RelationConnectorComponent } from '@obliczeniowo/elementary/connectors';\nimport { ComponentData } from '../../models/component-data';\nimport { ModellerService } from '../../services/modeller.service';\nimport { ModellerConnectorModel } from '../../models/modeller-connector.model';\nimport { BoxItemModel } from '../../models/box-item.model';\nimport { ModellerSpaceComponent } from '../../public-api';\n\n@Component({\n selector: 'obl-modeller-box',\n templateUrl: './modeller-box.component.html',\n styleUrls: ['./modeller-box.component.scss'],\n standalone: false\n})\nexport class ModellerBoxComponent {\n @Input() model?: BoxModel;\n /** world (global translation) */\n @Input() world: Point2D = new Point2D();\n /** local box only translation */\n @Input() translate: Point2D = new Point2D();\n /** translation for dragging this stuff */\n @Input() offset: Point2D = new Point2D();\n // to force display this box on top of any other one in view by set z-index\n @Input() index: number = 0;\n /** Unique per box type registration */\n @Input() id?: string;\n /** globally unique id as meany the same type boxes can exists */\n @Input() subId?: string;\n /** used only for 'input'/'output' type of model */\n @Input() inputModel?: { [key: string]: any };\n /** parent */\n @Input() parent?: ModellerSpaceComponent;\n /** */\n @Input() options?: { [key: string]: any }\n\n /** used only for 'input'/'output' type of model */\n @Output() outputChanged = new EventEmitterExt<any>();\n /** */\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n @Output() dragBox = new EventEmitterExt<{ mouse: MouseEvent, component: ModellerBoxComponent }>();\n\n @Output() connector = new EventEmitterExt<ModellerConnectorModel>();\n\n @Output() remove = new EventEmitterExt<ModellerBoxComponent>();\n /** remove connector by id */\n @Output() removeConnector = new EventEmitterExt<string>();\n\n protected connectors?: RelationConnectorComponent[];\n\n protected userModel?: { [key: string]: any } | any[];\n\n protected dynamic?: boolean = false;\n\n protected type: 'input' | 'button' = 'input';\n\n @HostBinding('style.z-index') get zIndex() {\n return this.index;\n }\n\n @HostBinding('style.transform') get transform() {\n return this.world.add(this.translate).add(this.offset).toCssTranslate('px');\n }\n\n @ViewChild('containerRef', { read: ViewContainerRef })\n containerRef!: ViewContainerRef;\n\n protected components: ComponentRef<any>[] = [];\n\n constructor(\n protected ref: ElementRef<HTMLElement>,\n public changes: ChangeDetectorRef,\n protected modeller: ModellerService\n ) { }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.model && this.containerRef || this.model && changes.containerRef) {\n this.reload();\n }\n if (changes.inputModel && this.inputModel && this.model && this.containerRef) {\n this.reload();\n }\n if (changes.options && this.containerRef) {\n this.userModel = { ...this.options?.userModel, ...this.userModel };\n this.reload();\n }\n if (changes.translate || changes.offset) {\n this.components.forEach(com => com.instance.recalc())\n }\n }\n\n ngAfterViewInit(): void {\n this.reload();\n }\n\n allConnectors(): RelationConnectorComponent[] {\n const connectors: RelationConnectorComponent[] = []\n this.components.forEach(component => {\n if (component.instance.left) {\n connectors.push(component.instance.left);\n }\n if (component.instance.right) {\n connectors.push(component.instance.right);\n }\n })\n\n return connectors;\n }\n\n getBoxItemModel(): BoxItemModel {\n const options: {[key: string]: any} = { };\n\n this.components.forEach(component => Object.assign(options, component.instance.options));\n\n options.userModel = this.userModel;\n\n return {\n id: this.id as string,\n subId: this.subId,\n options: {\n ...options,\n position: this.translate,\n }\n }\n }\n\n setConnectors(connectors: RelationConnectorComponent[]) {\n this.connectors = connectors;\n const arr = Array.from(this.connectors);\n this.components.forEach(component => {\n const id = component.instance.getFullId();\n\n component.instance.left = undefined;\n component.instance.right = undefined;\n\n arr.filter(conn => conn.connector?.left === id || conn.connector?.right === id).forEach(conn => {\n if (conn.connector?.left === id) {\n component.instance.setConnector('left', conn || undefined);\n }\n if (conn.connector?.right === id) {\n component.instance.setConnector('right', conn || undefined);\n }\n });\n })\n }\n\n protected clear() {\n this.components.forEach(component => {\n component.instance.connector.clearSubscriptions();\n component.instance.remove.clearSubscriptions();\n component.instance.changed.clearSubscriptions();\n component.instance.optionsChanged.clearSubscriptions();\n component.destroy();\n })\n\n this.components = [];\n }\n\n protected toDynamic() {\n this.dynamic = true;\n }\n\n protected transformUserModel() {\n if (Array.isArray(this.userModel)) {\n const first = this.userModel[0];\n\n const obj: { [key: string]: any } = {};\n\n const firstKeys = keys(first);\n\n firstKeys.forEach(key => obj[key] = []);\n\n this.userModel.forEach(item => {\n firstKeys.forEach(key => obj[key].push(item[key]));\n })\n return obj;\n }\n return this.userModel;\n }\n\n protected reload() {\n this.clear();\n\n this.userModel = this.userModel || this.options?.userModel;\n let userModel = this.transformUserModel();\n\n (this.model?.type === 'in-out' || !this.inputModel ? this.model?.components || [] :\n keys({ ...this.inputModel, ...userModel })\n .map(key => {\n return {\n type: this.modeller.getConnector(),\n id: key,\n value: this.model?.type === 'input' ? this.inputModel?.[key] : '',\n removable: !!(userModel || {})?.[key]\n };\n }) as ComponentData[]).forEach(\n com => {\n const component = this.containerRef.createComponent(\n com.type,\n {\n injector: this.containerRef.injector,\n }\n )\n\n component.instance.connector.subscribe((connector: any) => {\n this.connector.emit(connector)\n })\n\n component.instance.optionsChanged.subscribe(() => {\n this.optionsChanged.emit()\n })\n\n component.instance.changed.subscribe(async () => {\n if (this.model?.type === 'output') {\n const values: { [key: string]: any } = {}\n this.components.forEach(component => values[component.instance.id] = component.instance.value);\n if (!this.subId) {\n this.outputChanged.emit(values);\n }\n }\n })\n\n component.setInput('parent', this);\n\n component.setInput('id', com.id);\n component.setInput('subId', this.subId);\n component.setInput('inputOutputComponent', com?.inputOutputComponent);\n component.setInput('type', com.connectorType || this.model?.type || 'in-out');\n component.setInput('removable', com.removable);\n component.setInput('options', this.options);\n component.setInput('translations', this.model?.translations);\n\n this.setRemove(component, com);\n\n if ('input' === this.model?.type) {\n component.setInput('value', com.value)\n }\n // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit\n component.changeDetectorRef.detectChanges();\n\n this.components.push(component);\n }\n )\n }\n\n protected setRemove(component: ComponentRef<any>, com: ComponentData) {\n if (com.removable) {\n component.instance.remove.subscribe((id: string) => {\n if (this.userModel && !Array.isArray(this.userModel)) {\n delete this.userModel[id as any];\n };\n this.removeConnector.emit(`${this.id}:${this.subId}:${id}`);\n this.reload();\n this.options = { ...this.options, userModel: this.userModel };\n this.optionsChanged.emit();\n this?.parent?.setConnectors(this.restoreConnectors);\n })\n }\n }\n\n protected restoreConnectors() {\n if (this && this.connectors) {\n this.setConnectors(this.connectors)\n }\n }\n\n protected add(name?: string) {\n if (!name) {\n if (!this.userModel) {\n name = (keys(this.userModel || {}).length + 1).toString();\n } else if (!Array.isArray(this.userModel)) {\n let start: number = 0;\n do {\n start ++;\n name = start.toString() as string;\n } while((this.userModel || {})?.[start] === name)\n }\n }\n if (name === '' || keys({ ...this.inputModel, ...this.userModel }).find(key => key === name)) {\n return;\n }\n\n this.userModel = { ...this.userModel, [name as string]: name };\n this.reload();\n this.restoreConnectors();\n this.options = { ...this.options, userModel: this.userModel};\n this.optionsChanged.emit();\n }\n\n item(parentId: string, subId: string, id: string): ComponentRef<any> | undefined {\n return this.components.find(item => this.id === parentId && item.instance.subId === subId && item.instance.id === id);\n }\n\n recalc() {\n this.components.forEach(com => com.instance.recalc())\n }\n}\n","<div\n class=\"header\"\n (mousedown)=\"dragBox.emit({ mouse: $event, component: this })\"\n>\n {{ model?.translations?.[model?.title || ''] || model?.title }}\n @if (model?.type === 'in-out') {\n <button oblButton [icon]=\"'cancel'\" (click)=\"remove.emit(this)\"></button>\n }\n</div>\n\n<div>\n <ng-container #containerRef></ng-container>\n</div>\n\n@if (model?.type === 'output' || dynamic) {\n <div class=\"output\">\n @if (type === 'input') {\n <obl-input-wrapper [label]=\"modeller.getTranslation('Add new field')\">\n <input oblInput #newName type=\"text\"/>\n <button oblButton [icon]=\"'add'\" (click)=\"add(newName.value); newName.value = ''\" required suffix></button>\n </obl-input-wrapper>\n } @else {\n <button oblButton [icon]=\"'add'\" (click)=\"add()\">{{ modeller.getTranslation('Add new input') }}</button>\n }\n </div>\n}\n","import { Component, ComponentRef, ElementRef, Input, Output, SimpleChanges, Type, ViewChild, ViewContainerRef, ChangeDetectorRef } from '@angular/core';\nimport { Point2D } from '@obliczeniowo/elementary/classes';\nimport { ModellerBoxComponent } from '../modeller-box/modeller-box.component';\nimport { ModellerConnectorModel } from '../../models/modeller-connector.model';\nimport { RelationConnectorComponent } from '@obliczeniowo/elementary/connectors';\nimport { BoxItemType } from '../../public-api';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-connector-item',\n templateUrl: './connector-item.component.html',\n styleUrls: ['./connector-item.component.scss'],\n standalone: false\n})\nexport class ConnectorItemComponent {\n /** */\n @Input() left?: RelationConnectorComponent;\n /** */\n @Input() right?: RelationConnectorComponent;\n /** */\n @Input() parent?: ModellerBoxComponent;\n /** Unique per box type registration */\n @Input() id?: string;\n /** Globally unique id as meany the same type boxes can exists */\n @Input() subId?: string;\n /** */\n @Input() inputOutputComponent?: Type<any>;\n /** */\n @Input() type: BoxItemType = 'in-out';\n /** reserved only for input/output */\n @Input() value: any;\n /** if you can remove item */\n @Input() removable?: boolean;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [id: string]: any };\n\n @Output() connector = new EventEmitterExt<ModellerConnectorModel>();\n /** emit id to remove item */\n @Output() remove = new EventEmitterExt<string>();\n\n @Output() changed = new EventEmitterExt<any>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n protected component?: ComponentRef<any>;\n\n @ViewChild('containerRef', { read: ViewContainerRef })\n containerRef!: ViewContainerRef;\n\n getFullId(): string {\n return `${this.parent?.id}:${this.subId}:${this.id}`;\n }\n\n constructor(protected ref: ElementRef<HTMLElement>, protected changes: ChangeDetectorRef) {\n }\n\n setConnector(side: 'left' | 'right', connector?: RelationConnectorComponent) {\n const set = (component: ComponentRef<any>) => {\n if (fullId.includes('get-request')) {\n component.instance.get().then();\n } else {\n component.setInput('toTransform', this.value);\n }\n component.changeDetectorRef.detectChanges();\n }\n\n if (this[side]) {\n this[side]?.input.clearSubscriptions();\n }\n this[side] = connector;\n const fullId = this.getFullId();\n if (side === 'right') {\n this.right?.input.subscribe((value) => {\n this.value = value?.data;\n if (value) {\n this.changed.emit(this.value);\n }\n if (value?.stack.includes(fullId)) {\n throw new Error('Endless loop')\n }\n if (this.component) {\n set(this.component);\n } else {\n this.left?.input.next({ stack: [...(value?.stack || []), fullId], data: this.value });\n }\n\n this.changes.detectChanges();\n })\n } else {\n if (this.component) {\n set(this.component);\n\n this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), fullId], data: this.component.instance.value });\n } else {\n this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), fullId], data: this.value });\n this.changed.emit(this.value);\n }\n }\n this.recalc();\n }\n\n clicked(side: 'left' | 'right', connPoint: HTMLDivElement) {\n if (this.parent?.parent?.removeEmptyConnector(this.getFullId(), side === 'left' ? 'right' : 'left')) {\n setTimeout(() => this.clicked(side, connPoint));\n }\n\n if (this[side === 'left' ? 'right' : 'left']) {\n return;\n }\n\n const position = this.getPos(connPoint);\n\n this.connector.emit({\n [side === 'left' ? 'right' : 'left']: this.getFullId(),\n [side === 'left' ? 'end' : 'start']: position\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.inputOutputComponent && this.containerRef || this.inputOutputComponent && changes.containerRef) {\n this.reload();\n }\n if (changes.options && changes.containerRef) {\n this.reload();\n }\n if (changes.value) {\n this.changed.emit(this.value);\n if (this.component) {\n this.component.setInput('toTransform', this.value);\n this.component.changeDetectorRef.detectChanges();\n } else {\n this.left?.input.next({ stack: [...(this.right?.input.getValue()?.stack || []), this.getFullId()], data: this.value });\n }\n }\n }\n\n ngAfterViewInit(): void {\n this.reload();\n }\n\n getPos(el: HTMLDivElement): Point2D {\n let parent: HTMLElement | null = el;\n let position = new Point2D(el.offsetLeft, el.offsetTop);\n\n do {\n parent = parent.parentElement;\n\n if (parent) {\n position = position.add(new Point2D(parent.offsetLeft, parent.offsetTop));\n }\n if (parent?.parentElement?.nodeName === 'OBL-MODELLER-SPACE') {\n break;\n }\n } while (parent);\n\n return position.add(this.parent?.translate || new Point2D()).add(this.parent?.offset || new Point2D()).add(new Point2D(5, -18));\n }\n\n recalc() {\n if (this.left) {\n const left = this.ref.nativeElement.querySelector('div.output-connector') as HTMLDivElement;\n if (this.left.connector) {\n (this.left.connector as any).start = this.getPos(left);\n }\n }\n\n if (this.right) {\n const right = this.ref.nativeElement.querySelector('div.input-connector') as HTMLDivElement;\n if (this.right.connector) {\n (this.right.connector as any).end = this.getPos(right);\n }\n }\n }\n\n protected transformed = (value: any) => {\n this.left?.input.next({ stack: [...(value?.stack || []), this.getFullId], data: value });\n this.options = this.component?.instance.options;\n if (!value) {\n this.value = undefined;\n this.changes.detectChanges();\n }\n }\n\n protected reload() {\n const { component, inputOutputComponent } = this;\n if (component) {\n component.instance.transformed.clearSubscriptions();\n component.instance.optionsChanged.clearSubscriptions();\n component.instance.changed.clearSubscriptions();\n component.destroy();\n }\n if (inputOutputComponent) {\n this.component = this.containerRef.createComponent(\n inputOutputComponent,\n {\n injector: this.containerRef.injector,\n }\n )\n\n this.component.instance.transformed.subscribe(this.transformed);\n this.component.instance.optionsChanged.subscribe(() => this.optionsChanged.emit());\n this.component.setInput('toTransform', this.value);\n this.component.setInput('options', this.options);\n this.component.setInput('translations', this.translations);\n\n this.component.changeDetectorRef.detectChanges();\n }\n }\n}\n","@if (['in-out', 'output'].includes(type)) {\n <div\n class=\"input input-connector\"\n [class.connected]=\"right\"\n #input\n (click)=\"clicked('left', input)\"\n >\n &gt;\n </div>\n}\n<div class=\"container\">\n @if (!inputOutputComponent) {\n <div>{{ id }}: {{ value | json }}</div>\n }\n <ng-container #containerRef></ng-container>\n</div>\n@if (['in-out', 'input'].includes(type)) {\n <div\n class=\"output output-connector\"\n [class.connected]=\"left\"\n #output\n (click)=\"clicked('right', output)\"\n >\n &lt;\n </div>\n}\n\n@if (removable) {\n <button\n oblButton\n [icon]=\"'cancel'\"\n (click)=\"remove.emit(id)\"\n ></button>\n}","import { Component, Input, Output, SimpleChanges } from '@angular/core';\nimport { DropdownSelectItem } from '@obliczeniowo/elementary/dropdown-select';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-integer-filter-connector',\n templateUrl: './integer-filter-connector.component.html',\n styleUrls: ['./integer-filter-connector.component.scss'],\n standalone: false\n})\nexport class IntegerFilterConnectorComponent implements OblConverter {\n @Input() toTransform?: number | number[] | undefined;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [id: string]: string };\n\n @Output() transformed = new EventEmitterExt<number | number[] | undefined>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n value: number | number[] | undefined;\n\n items: DropdownSelectItem<string>[] = [\n {\n id: 'to-floor',\n text: 'To floor',\n },\n {\n id: 'to-ceil',\n text: 'To ceil',\n },\n ]\n\n selected = this.items[0].id;\n\n changed(item: DropdownSelectItem<any>) {\n this.selected = item.id;\n this.transform();\n this.optionsChanged.emit();\n }\n\n transform() {\n if (this.toTransform) {\n this.options = { ...this.options, selected: this.selected };\n const transform = (value: number) => {\n switch (this.selected) {\n case 'to-floor': {\n return Math.floor(value);\n }\n case 'to-ceil': {\n return Math.ceil(value);\n }\n }\n return undefined;\n }\n if (typeof this.toTransform === 'number') {\n this.value = transform(this.toTransform) || 0;\n } else if (this.toTransform instanceof Array) {\n this.value = this.toTransform.map((value => transform(value) || 0));\n }\n } else {\n this.value = undefined;\n }\n this.transformed.emit(this.value);\n }\n\n ngOnInit() {\n this.items.forEach((item, index) => {\n this.items[index].text = this.translations?.[item.text] || item.text;\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.toTransform) {\n this.transform();\n }\n if (changes.options) {\n this.selected = this?.options?.selected ?? this.selected;\n this.transform();\n }\n }\n\n ngOnDestroy(): void {\n this.transformed.unsubscribe();\n }\n}\n","<obl-dropdown-select\n [items]=\"items\"\n (changed)=\"changed($event)\"\n [select]=\"selected\"\n [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n","import { Component, Input, Output, SimpleChanges } from '@angular/core';\nimport { ElementaryMath } from '@obliczeniowo/elementary/math';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-convert-to-histogram',\n templateUrl: './convert-to-histogram.component.html',\n styleUrls: ['./convert-to-histogram.component.scss'],\n standalone: false\n})\nexport class ConvertToHistogramComponent implements OblConverter {\n @Input() toTransform?: number[] | undefined;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [en: string]: string };\n\n @Output() transformed = new EventEmitterExt<number[] | undefined>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n value?: number[];\n\n protected ranges: number = 5;\n\n transform() {\n if (this.toTransform && this.toTransform instanceof Array) {\n const minMax = ElementaryMath.getMinMax(this.toTransform);\n const dm = (minMax.max - minMax.min) / this.ranges;\n\n if (dm === 0) {\n this.value = [this.toTransform.length];\n return;\n }\n\n const value = new Array(this.ranges).fill(0);\n\n this.toTransform.forEach(item => value[Math.min(Math.floor((item - minMax.min) / dm), this.ranges - 1)] += 1);\n\n this.value = value;\n } else {\n this.value = undefined;\n }\n this.transformed.emit(this.value);\n }\n\n changed(event: any) {\n this.ranges = +event.value;\n this.options = { ...this.options, ranges: this.ranges }\n this.transform();\n this.optionsChanged.emit();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.toTransform) {\n this.transform();\n }\n if (changes.options) {\n this.ranges = this?.options?.ranges || this.ranges;\n this.transform();\n }\n }\n\n ngOnDestroy(): void {\n this.transformed.unsubscribe();\n }\n}\n","<obl-input-wrapper [label]=\"translations?.Range || 'Range'\">\n <input type=\"number\" oblInput [value]=\"ranges\" (change)=\"changed($event.target)\" min=\"2\" />\n</obl-input-wrapper>","import { Component, Input, Output, SimpleChanges } from '@angular/core';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-range-filter',\n templateUrl: './range-filter.component.html',\n styleUrls: ['./range-filter.component.scss'],\n standalone: false\n})\nexport class RangeFilterComponent implements OblConverter {\n @Input() toTransform?: number[] | undefined;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [en: string]: string };\n\n @Output() transformed = new EventEmitterExt<number[]>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n max: number = 10;\n\n min: number = 0;\n\n value: number[] | undefined;\n\n updateOptions() {\n this.options = { ...this.options, min: this.min, max: this.max };\n }\n\n setMin(event: any) {\n this.min = +(event.target.value ?? this.min);\n this.updateOptions();\n this.transform();\n this.optionsChanged.emit();\n }\n\n setMax(event: any) {\n this.max = +(event.target.value ?? this.max);\n this.updateOptions();\n this.transform();\n this.optionsChanged.emit();\n }\n\n transform() {\n if (this.toTransform instanceof Array) {\n this.value = this.toTransform.filter(value => value >= this.min && value <= this.max);\n } else {\n this.value = undefined;\n }\n this.transformed.emit(this.value);\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.toTransform) {\n this.transform();\n }\n if (changes.options) {\n this.min = this.options?.min || this.min;\n this.max = this.options?.max || this.max;\n this.transform();\n }\n }\n}\n","<obl-input-wrapper [label]=\"translations?.['Min'] || 'Min'\" [step]=\"1\">\n <input type=\"number\" oblInput [value]=\"min\" [max]=\"max\" step=\"any\" (change)=\"setMin($event)\" />\n</obl-input-wrapper>\n\n<obl-input-wrapper [label]=\"translations?.['Max'] || 'Max'\" [step]=\"1\">\n <input type=\"number\" oblInput [value]=\"max\" [min]=\"min\" step=\"any\" (change)=\"setMax($event)\" />\n</obl-input-wrapper>","import { Component, Input, Output, SimpleChanges } from '@angular/core';\n\nimport { DropdownSelectItem } from '@obliczeniowo/elementary/dropdown-select';\nimport { firstToUpper, allWordsFirstToUpper, toCamelCase } from '@obliczeniowo/elementary/utils';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-string-converter',\n templateUrl: './string-converter.component.html',\n styleUrls: ['./string-converter.component.scss'],\n standalone: false\n})\nexport class StringConverterComponent implements OblConverter {\n @Input() toTransform?: string;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [en: string]: string };\n\n @Output() transformed = new EventEmitterExt<string | string[]>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n items: DropdownSelectItem<string>[] = [\n {\n id: 'to-upper-case',\n text: 'To upper case',\n },\n {\n id: 'to-lower-case',\n text: 'To lower case',\n },\n {\n id: 'first-to-upper-case',\n text: 'First letter to upper case'\n },\n {\n id: 'word-first-to-upper-case',\n text: 'Word first letter to upper case'\n },\n {\n id: 'camel-case',\n text: 'To camel case'\n },\n {\n id: 'split',\n text: 'Split',\n },\n {\n id: 'JSON-parse',\n text: 'JSON parse',\n },\n {\n id: 'substring',\n text: 'Substring',\n },\n ]\n\n selected = this.items[0].id;\n\n lastError: any;\n\n value: string | string[] | undefined;\n\n protected split: string = ' ';\n protected start: number = 0;\n protected end: number = 5;\n\n transform() {\n if (this.toTransform && typeof this.toTransform === 'string') {\n switch (this.selected) {\n case 'to-upper-case': {\n this.value = this.toTransform.toUpperCase();\n }\n break;\n case 'to-lower-case': {\n this.value = this.toTransform.toLowerCase();\n }\n break;\n case 'first-to-upper-case': {\n this.value = firstToUpper(this.toTransform);\n }\n break;\n case 'word-first-to-upper-case': {\n this.value = allWordsFirstToUpper(this.toTransform);\n }\n break;\n case 'camel-case': {\n this.value = toCamelCase(this.toTransform);\n }\n break;\n case 'split': {\n this.value = this.toTransform.split(this.split);\n }\n break;\n case 'JSON-parse': {\n try {\n this.value = JSON.parse(this.toTransform);\n } catch (error) {\n this.value = undefined;\n this.lastError = new Error('String json parse failure');\n }\n }\n break;\n case 'substring': {\n this.value = this.toTransform.substring(this.start, this.end);\n }\n break;\n }\n this.transformed.emit(this.value);\n } else {\n this.value = undefined;\n this.transformed.emit(this.value);\n this.lastError = new Error('Value is undefined or is not a string');\n }\n }\n\n ngOnInit() {\n this.items.forEach((item, index) => {\n this.items[index].text = this.translations?.[item.text] || item.text;\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.toTransform) {\n this.transform();\n }\n if (changes.options) {\n this.selected = this.options?.selected || this.selected;\n this.split = this.options?.split || this.split;\n this.start = this.options?.start || this.start;\n this.end = this.options?.end || this.end;\n this.transform();\n }\n }\n\n changed(item: DropdownSelectItem<any>) {\n this.selected = item.id;\n this.options = { ...this.options, selected: this.selected };\n this.transform();\n this.optionsChanged.emit();\n }\n\n splitChanged(event: any) {\n this.split = event.target.value;\n this.options = { ...this.options, split: this.split };\n this.transform();\n this.optionsChanged.emit();\n }\n\n startChanged(event: any) {\n this.start = event.target.value;\n this.options = { ...this.options, start: this.start };\n this.transform();\n this.optionsChanged.emit();\n }\n\n endChanged(event: any) {\n this.end = event.target.value;;\n this.options = { ...this.options, end: this.end };\n this.transform();\n this.optionsChanged.emit();\n }\n\n ngOnDestroy(): void {\n this.transformed.unsubscribe();\n }\n}\n","<obl-dropdown-select\n [items]=\"items\"\n [select]=\"selected\"\n (changed)=\"changed($event)\"\n [label]=\"translations?.['Operation type'] || 'Operation type'\"\n></obl-dropdown-select>\n\n@if (selected === 'split') {\n <obl-input-wrapper [label]=\"translations?.['Split by'] || 'Split by'\">\n <input type=\"text\" [value]=\"split\" (change)=\"splitChanged($event)\" oblInput />\n </obl-input-wrapper>\n}\n\n@if (selected === 'substring') {\n <obl-input-wrapper [label]=\"translations?.Start || 'Start'\" [step]=\"1\">\n <input\n type=\"number\"\n [value]=\"start\"\n (change)=\"startChanged($event)\"\n oblInput\n />\n </obl-input-wrapper>\n\n <obl-input-wrapper [label]=\"translations?.End || 'End'\" [step]=\"1\">\n <input type=\"number\" [value]=\"end\" (change)=\"endChanged($event)\" oblInput />\n </obl-input-wrapper>\n}\n","import { Component } from '@angular/core';\n\nimport { keys } from '@obliczeniowo/elementary/objects';\n\nimport { ModellerBoxComponent } from '../modeller-box/modeller-box.component';\nimport { ComponentData } from '../../models/component-data';\n\n@Component({\n selector: 'obl-split-box',\n templateUrl: '../modeller-box/modeller-box.component.html',\n styleUrls: ['../modeller-box/modeller-box.component.scss'],\n standalone: false\n})\nexport class SplitBoxComponent extends ModellerBoxComponent {\n\n protected reload() {\n this.clear();\n\n const prepare: { [key: string]: any } | { [key: string]: any }[] = { object: 0, ...this.transformUserModel() };\n\n (keys(prepare)\n .map((key, index) => {\n return {\n type: this.modeller.getConnector(),\n id: key,\n value: prepare[key],\n connectorType: index ? 'input' : 'output'\n };\n }) as ComponentData[]).forEach(\n (com, index) => {\n const component = this.containerRef.createComponent(\n com.type,\n {\n injector: this.containerRef.injector,\n }\n )\n\n component.instance.connector.subscribe((connector: any) => {\n this.connector.emit(connector)\n })\n\n if (index === 0) {\n component.instance.changed.subscribe((value: any) => {\n if (typeof value === 'string' || typeof value === 'number'\n || JSON.stringify(this.userModel) === JSON.stringify(value)) {\n return;\n }\n\n this.userModel = value;\n this.reload();\n setTimeout(() => this.setConnectors(this.connectors || []));\n })\n }\n\n component.instance.changed.subscribe(() => {\n if (this.model?.type === 'output') {\n const values: { [key: string]: any } = {}\n this.components.forEach(component => values[component.instance.id] = component.instance.value);\n this.outputChanged.emit(values);\n }\n })\n\n component.setInput('parent', this);\n\n component.setInput('id', com.id);\n component.setInput('subId', this.subId);\n component.setInput('inputOutputComponent', com?.inputOutputComponent);\n component.setInput('type', com.connectorType || this.model?.type || 'in-out');\n component.setInput('removable', com.removable);\n component.setInput('options', this.options);\n\n if (index) {\n component.setInput('value', com.value)\n }\n\n if (com.removable) {\n component.instance.remove.subscribe((id: string) => {\n if (this.userModel && !Array.isArray(this.userModel)) {\n delete this.userModel[id as any];\n };\n this.removeConnector.emit(`${this.id}:${this.subId}:${id}`);\n this.reload();\n this.restoreConnectors();\n this.options = { ...this.options, userModel: this.userModel};\n this.optionsChanged.emit();\n })\n }\n\n if ('input' === this.model?.type) {\n component.setInput('value', com.value)\n }\n // required to start triggering hooks without that is not trigger ngOnChanges/ngOnInit/ngAfterViewInit\n component.changeDetectorRef.detectChanges();\n\n this.components.push(component);\n }\n )\n }\n}\n","import { Component, Input, Output } from '@angular/core';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-value-input',\n templateUrl: './value-input.component.html',\n styleUrls: ['./value-input.component.scss'],\n standalone: false\n})\nexport class ValueInputComponent implements OblConverter {\n @Input() id!: string;\n\n @Input() translations?: { [en: string]: string };\n\n @Input() toTransform?: number[] | number | undefined;\n\n @Input() header = 'Value';\n\n @Input() options?: { [en: string]: any };\n\n @Output() transformed = new EventEmitterExt<number[] | number | undefined>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n transform() {\n this.transformed.emit(this.toTransform);\n }\n}\n","{{ translations?.[header || ''] || header }} {{ toTransform | json }}\n","import { Component } from '@angular/core';\nimport { ModellerBoxComponent } from '../modeller-box/modeller-box.component';\nimport { RelationConnectorComponent } from '@obliczeniowo/elementary/connectors';\n\n@Component({\n selector: 'obl-math-box',\n templateUrl: '../modeller-box/modeller-box.component.html',\n styleUrls: ['../modeller-box/modeller-box.component.scss'],\n standalone: false\n})\nexport class MathBoxComponent extends ModellerBoxComponent {\n values?: { left?: number, right?: number };\n\n setConnectors(connectors: RelationConnectorComponent[]) {\n super.setConnectors(connectors);\n this.components?.[2].instance.component.setInput('toTransform', this.values);\n }\n\n protected reload() {\n super.reload();\n\n if (this.components.length === 3) {\n this.components[0].instance.component.setInput('header', 'Left:');\n this.components[1].instance.component.setInput('header', 'Right:');\n\n this.components.forEach(component => component.setInput('translations', this.model?.translations));\n\n this.components[0].instance.changed.subscribe((value: any) => {\n this.values = { ...this.values, left: value };\n this.components[2].instance.component.setInput('toTransform', this.values);\n this.components[2].changeDetectorRef.detectChanges();\n })\n this.components[1].instance.changed.subscribe((value: any) => {\n this.values = { ...this.values, right: value };\n this.components[2].instance.component.setInput('toTransform', this.values);\n this.components[2].changeDetectorRef.detectChanges();\n })\n }\n }\n}\n","import { Component, Input, Output, SimpleChanges } from '@angular/core';\nimport { DropdownSelectItem } from '@obliczeniowo/elementary/dropdown-select';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-math-operator',\n templateUrl: './math-operator.component.html',\n styleUrls: ['./math-operator.component.scss'],\n standalone: false\n})\nexport class MathOperatorComponent implements OblConverter {\n @Input() toTransform?: { left?: number | number[], right?: number | number[] };\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [en: string]: string };\n\n @Output() transformed = new EventEmitterExt<number | number[]>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n items: DropdownSelectItem<string>[] = [\n {\n id: 'add',\n text: 'Add',\n },\n {\n id: 'subtract',\n text: 'Subtract',\n },\n {\n id: 'multiply',\n text: 'Multiply'\n },\n {\n id: 'divide',\n text: 'Divide'\n },\n {\n id: 'power',\n text: 'Power'\n },\n {\n id: 'modulo',\n text: 'Modulo',\n }\n ]\n\n selected = this.items[0].id;\n\n value: number | number[] | undefined;\n\n lastError: any;\n\n transform() {\n const { left, right } = this.toTransform || {};\n\n const operation = (\n left: number | number[],\n right: number | number[],\n cb: (left: number, right: number) => number\n ) => {\n\n const leftNumeric = typeof left === 'number';\n const rightNumeric = typeof right === 'number';\n\n if (leftNumeric && rightNumeric) {\n return cb(left, right);\n } else if (!leftNumeric && !rightNumeric) {\n const result: number[] = [];\n (left as Array<number>).forEach((n, index) => {\n result.push(cb(n, (right as number[])[index]));\n });\n return result;\n\n } else if (rightNumeric) {\n const result: number[] = [];\n (left as Array<number>).forEach(n => {\n result.push(cb(n, right as number));\n });\n return result;\n } else {\n const result: number[] = [];\n (right as Array<number>).forEach(n => {\n result.push(cb(left as number, n));\n });\n return result;\n }\n }\n\n const typed = (value: any) => typeof value === 'number' || Array.isArray(value);\n\n if (left !== undefined && right !== undefined && typed(left) && typed(right)) {\n switch (this.selected) {\n case 'add': {\n this.value = operation(left, right, (left: number, right: number) => left + right)\n }\n break;\n case 'subtract': {\n this.value = operation(left, right, (left: number, right: number) => left - right)\n }\n break;\n case 'multiply': {\n this.value = operation(left, right, (left: number, right: number) => left * right)\n }\n break;\n case 'divide': {\n this.value = operation(left, right, (left: number, right: number) => left / right)\n }\n break;\n case 'power': {\n this.value = operation(left, right, (left: number, right: number) => Math.pow(left, right));\n }\n break;\n case 'modulo': {\n this.value = operation(left, right, (left: number, right: number) => left % right)\n }\n }\n this.transformed.emit(this.value);\n } else {\n this.value = undefined;\n this.transformed.emit(this.value);\n this.lastError = new Error('Value is undefined or is not a number')\n }\n }\n\n ngOnInit() {\n this.items.forEach((item, index) => {\n this.items[index].text = this.translations?.[item.text] || item.text;\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.toTransform) {\n this.transform();\n }\n if (changes.options) {\n this.selected = this.options?.selected || this.selected;\n this.transform();\n }\n }\n\n changed(item: DropdownSelectItem<any>) {\n this.selected = item.id;\n this.options = { ...this.options, selected: this.selected };\n this.transform();\n this.optionsChanged.emit();\n }\n}\n","<obl-dropdown-select\n [items]=\"items\"\n [select]=\"selected\"\n (changed)=\"changed($event)\"\n [label]=\"translations?.['Operator type'] || 'Operator type'\"\n></obl-dropdown-select>\n","import { Component, Input, Output, SimpleChanges } from '@angular/core';\nimport { DropdownSelectItem } from '@obliczeniowo/elementary/dropdown-select';\nimport { OblConverter } from '../../models/obl-connector';\nimport { EventEmitterExt } from '@obliczeniowo/elementary/rx-js-ext';\n\n@Component({\n selector: 'obl-const-or-value',\n templateUrl: './const-or-value.component.html',\n styleUrls: ['./const-or-value.component.scss'],\n standalone: false\n})\nexport class ConstOrValueComponent implements OblConverter {\n @Input() toTransform: number = Math.PI;\n /** */\n @Input() options?: { [key: string]: any };\n /** */\n @Input() translations?: { [en: string]: string };\n\n @Output() transformed = new EventEmitterExt<string | number | number[]>();\n\n @Output() optionsChanged = new EventEmitterExt<void>();\n\n items: DropdownSelectItem<string>[] = [\n {\n id: 'pi',\n text: 'Pi π',\n },\n {\n id: 'e',\n text: 'e',\n },\n {\n id: 'gold',\n text: 'Gold'\n },\n {\n id: 'earth-gravity',\n text: 'Earth gravity'\n },\n {\n id: 'gravity-const',\n text: 'Gravity const'\n },\n {\n id: 'light-speed',\n text: 'Light speed',\n },\n {\n id: 'variable',\n text: 'Numeric variable'\n },\n {\n id: 'planck-constant',\n text: 'Planck constant'\n },\n {\n id: 'apery-const',\n text: 'Apéry const'\n },\n {\n id: 'newman-const',\n text: 'Newman const'\n },\n {\n id: 'string',\n text: 'Text value'\n },\n {\n id: 'json-value',\n text: 'JSON variable'\n }\n ]\n\n selected = this.items[0].id;\n\n value: number | string | any | undefined;\n\n lastError: any;\n\n values: { [key: string]: number | string } = {\n pi: Math.PI,\n e: Math.E,\n gold: (Math.sqrt(5) - 1) / 2,\n 'earth-gravity': 9.8065,\n 'gravity-const': 6.67259e-11,\n 'light-speed': 299792458,\n 'planck-constant': 6.62807015e-24,\n 'apery-const': 1.2020569031595942853997381,\n 'newman-const': 2.7e-9,\n variable: 0,\n string: '',\n 'json-value': '{}'\n }\n\n transform() {\n try {\n this.value = this.selected === 'json-value' ? JSON.parse(this.values?.[this.selected] as string || '{}') : this.values[this.selected];\n this.transformed.emit(this.value);\n } catch (e) {\n this.transformed.emit(undefined);\n }\n }\n\n ngOnInit() {\n this.items.forEach((item, index) => {\n this.items[index].text = this.translations?.[item.text] || item.text;\n });\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.options) {\n this.selected = this.options?.selected || this.selected;\n this.values['variable'] = this.options?.value || 0;\n this.values['string'] = this.options?.string || '';\n this.values['json-value'] = this.options?.['json-value'] || '{}';\n this.transform();\n }\n }\n\n changed(item: DropdownSelectItem<any>) {\n this.selected = item.id;\n this.options = { ...this.options, selected: item.id };\n this.transform();\n this.optionsChanged.emit();\n }\n\n variableChanged(variable: any) {\n this.values['variable'] = variable.target.valueAsNumber;\n this.options = { ...this.options, value: this.values['variable'] };\n this.transform();\n this.optionsChanged.emit();\n }\n\n stringChanged(variable: any) {\n this.values['string'] = variable.target.value;\n this.options = { ...this.options, string: this.values['string'] };\n this.transform();\n this.optionsChanged.emit();\n }\n\n jsonChanged(variable: any) {\n this.values['json-value'] = variable.target.value;\n this.options = { ...this.options, 'json-value': this.values['json-value'] };\n this.transform();\n this.optionsChanged.emit();\n }\n}\n","<obl-dropdown-select\n [items]=\"items\"\n [select]=\"selected\"\n (changed)=\"changed($event)\"\n [label]=\"translations?.['Constant / variable:'] || 'Constant / variable:'\"\n></obl-dropdown-select>\n\n@if (selected === 'variable') {\n <obl-input-wrapper\n [label]=\"translations?.['Value:'] || 'Value:'\"\n [step]=\"1\"\n >\n <input\n type=\"number\"\n [value]=\"values['variable']\"\n (change)=\"variableChanged($event)\"\n (keyup)=\"variableChanged($event)\"\n o