@rocketshow/designer 1.51.0 → 1.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, HostListener, ViewChild, Component, Pipe, EventEmitter, Input, Output, ChangeDetectionStrategy, ViewEncapsulation, NgModule } from '@angular/core';
2
+ import { Injectable, HostListener, ViewChild, Component, Pipe, EventEmitter, Output, Input, Directive, ChangeDetectionStrategy, ViewEncapsulation, NgModule } from '@angular/core';
3
3
  import * as i4 from '@ngx-translate/core';
4
4
  import { TranslateModule } from '@ngx-translate/core';
5
5
  import * as i1$1 from 'ngx-bootstrap/modal';
@@ -26,13 +26,12 @@ import * as i3$2 from '@angular/forms';
26
26
  import { FormsModule } from '@angular/forms';
27
27
  import * as i11 from 'ngx-bootstrap/popover';
28
28
  import { PopoverModule } from 'ngx-bootstrap/popover';
29
+ import Sortable from 'sortablejs';
29
30
  import * as i10 from 'ngx-bootstrap/typeahead';
30
31
  import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
31
32
  import * as i3$3 from 'ngx-bootstrap-slider';
32
33
  import { NgxBootstrapSliderModule } from 'ngx-bootstrap-slider';
33
34
  import * as i9 from '@angular/common';
34
- import * as i7 from 'ngx-sortablejs-plus';
35
- import { SortablejsModule } from 'ngx-sortablejs-plus';
36
35
  import * as i5$1 from 'ngx-bootstrap/accordion';
37
36
  import { AccordionModule } from 'ngx-bootstrap/accordion';
38
37
  import { KEYS, TREE_ACTIONS, TreeModule } from '@ali-hm/angular-tree-component';
@@ -5185,6 +5184,122 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
5185
5184
  args: ['document:keydown.enter', ['$event']]
5186
5185
  }] } });
5187
5186
 
5187
+ const DEFAULT_OPTIONS = {
5188
+ animation: 150,
5189
+ draggable: ">*:not(.no-sortjs)",
5190
+ filter: ".no-sortjs, .no-sortjs *",
5191
+ handle: ".list-sort-handle",
5192
+ preventOnFilter: false,
5193
+ };
5194
+ class SortablejsDirective {
5195
+ constructor(element, zone) {
5196
+ this.element = element;
5197
+ this.zone = zone;
5198
+ this.sortablejsInit = new EventEmitter();
5199
+ }
5200
+ ngAfterViewInit() {
5201
+ const container = this.sortablejsContainer
5202
+ ? this.element.nativeElement.querySelector(this.sortablejsContainer)
5203
+ : this.element.nativeElement;
5204
+ if (!(container instanceof HTMLElement)) {
5205
+ return;
5206
+ }
5207
+ this.createTimer = setTimeout(() => {
5208
+ this.zone.runOutsideAngular(() => {
5209
+ this.sortableInstance = Sortable.create(container, this.options);
5210
+ });
5211
+ this.sortablejsInit.emit(this.sortableInstance);
5212
+ }, 0);
5213
+ }
5214
+ ngOnDestroy() {
5215
+ if (this.createTimer) {
5216
+ clearTimeout(this.createTimer);
5217
+ }
5218
+ this.sortableInstance?.destroy();
5219
+ }
5220
+ get options() {
5221
+ const { onMove: _onMove, ...userOptions } = this.sortablejsOptions || {};
5222
+ const userOnEnd = userOptions.onEnd;
5223
+ const userOnUpdate = userOptions.onUpdate;
5224
+ return {
5225
+ ...userOptions,
5226
+ ...DEFAULT_OPTIONS,
5227
+ onEnd: (event) => {
5228
+ if (userOnEnd) {
5229
+ this.zone.run(() => userOnEnd(event));
5230
+ }
5231
+ },
5232
+ onUpdate: (event) => {
5233
+ this.zone.run(() => {
5234
+ this.restoreDomOrder(event);
5235
+ this.reorder(event);
5236
+ userOnUpdate?.(event);
5237
+ });
5238
+ },
5239
+ };
5240
+ }
5241
+ reorder(event) {
5242
+ if (!this.sortablejs) {
5243
+ return;
5244
+ }
5245
+ const oldIndex = this.indexFromEvent(event, "old");
5246
+ const newIndex = this.indexFromEvent(event, "new");
5247
+ if (oldIndex === undefined ||
5248
+ oldIndex === null ||
5249
+ newIndex === undefined ||
5250
+ newIndex === null ||
5251
+ oldIndex === newIndex ||
5252
+ oldIndex < 0 ||
5253
+ newIndex < 0 ||
5254
+ oldIndex >= this.sortablejs.length ||
5255
+ newIndex >= this.sortablejs.length) {
5256
+ return;
5257
+ }
5258
+ const [movedItem] = this.sortablejs.splice(oldIndex, 1);
5259
+ this.sortablejs.splice(newIndex, 0, movedItem);
5260
+ }
5261
+ restoreDomOrder(event) {
5262
+ const oldIndex = this.indexFromEvent(event, "old");
5263
+ const item = event.item;
5264
+ const container = item?.parentElement;
5265
+ if (!item ||
5266
+ !container ||
5267
+ oldIndex === undefined ||
5268
+ oldIndex === null ||
5269
+ oldIndex < 0) {
5270
+ return;
5271
+ }
5272
+ const draggableChildren = Array.from(container.children).filter((child) => child instanceof HTMLElement &&
5273
+ child !== item &&
5274
+ !child.classList.contains("no-sortjs"));
5275
+ const firstNoSortItem = Array.from(container.children).find((child) => child instanceof HTMLElement && child.classList.contains("no-sortjs"));
5276
+ const referenceNode = draggableChildren[oldIndex] || firstNoSortItem || null;
5277
+ container.insertBefore(item, referenceNode);
5278
+ }
5279
+ indexFromEvent(event, direction) {
5280
+ const draggableIndex = direction === "old" ? event.oldDraggableIndex : event.newDraggableIndex;
5281
+ const index = direction === "old" ? event.oldIndex : event.newIndex;
5282
+ return draggableIndex ?? index;
5283
+ }
5284
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SortablejsDirective, deps: [{ token: i0.ElementRef }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
5285
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.16", type: SortablejsDirective, isStandalone: false, selector: "[sortablejs]", inputs: { sortablejs: "sortablejs", sortablejsContainer: "sortablejsContainer", sortablejsOptions: "sortablejsOptions" }, outputs: { sortablejsInit: "sortablejsInit" }, ngImport: i0 }); }
5286
+ }
5287
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SortablejsDirective, decorators: [{
5288
+ type: Directive,
5289
+ args: [{
5290
+ selector: "[sortablejs]",
5291
+ standalone: false,
5292
+ }]
5293
+ }], ctorParameters: () => [{ type: i0.ElementRef }, { type: i0.NgZone }], propDecorators: { sortablejs: [{
5294
+ type: Input
5295
+ }], sortablejsContainer: [{
5296
+ type: Input
5297
+ }], sortablejsOptions: [{
5298
+ type: Input
5299
+ }], sortablejsInit: [{
5300
+ type: Output
5301
+ }] } });
5302
+
5188
5303
  class FixturePoolComponent {
5189
5304
  constructor(bsModalRef, fixtureService, uuidService, projectService, previewService, translateService, toastrService, presetService, configService, modalService) {
5190
5305
  this.bsModalRef = bsModalRef;
@@ -5523,11 +5638,11 @@ class FixturePoolComponent {
5523
5638
  this.ok();
5524
5639
  }
5525
5640
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FixturePoolComponent, deps: [{ token: i1$1.BsModalRef }, { token: FixtureService }, { token: UuidService }, { token: ProjectService }, { token: PreviewService }, { token: i4.TranslateService }, { token: i3$1.ToastrService }, { token: PresetService }, { token: ConfigService }, { token: i1$1.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
5526
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FixturePoolComponent, isStandalone: false, selector: "lib-app-fixture-pool", host: { listeners: { "window:mouseup": "mouseUp($event)", "document:keydown.enter": "handleKeyboardEvent($event)" } }, ngImport: i0, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input\n type=\"text\"\n class=\"form-control input-block mb-3\"\n id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\"\n />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{ profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a\n class=\"mt-2 btn btn-secondary btn-sm float-right\"\n href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\"\n role=\"button\"\n >\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button\n type=\"button\"\n class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\"\n (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\"\n role=\"button\"\n >\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' | translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <!-- TODO sortablejs breaks sortable lists in base designer view, as soon as it disappears -->\n <!-- Reproduce: select a fixture, deselect a fixture, open pool, close pool without changes, fixture is \"half\"-selected again -->\n <!-- <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\"> -->\n <div class=\"list-group list-group-flush\">\n @for (fixture of fixturePool; track fixture) {\n <div\n class=\"list-group-item\"\n [class.active]=\"fixture == selectedFixture\"\n (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\"\n >\n <div class=\"row\">\n <!-- <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div> -->\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span\n >{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track $index; let i = $index) {\n <div\n class=\"dmx-channel\"\n [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\"\n [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\"\n (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\"\n [attr.data-index]=\"i\"\n popover=\"{{ i + 1 }}\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n >\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\" [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' | translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\" id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\"\n >\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\"\n >\n @for (channel of dmxChannels; track $index; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>\n", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"], dependencies: [{ kind: "directive", type: i3$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i11.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "pipe", type: ArraySortPipe, name: "sort" }] }); }
5641
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FixturePoolComponent, isStandalone: false, selector: "lib-app-fixture-pool", host: { listeners: { "window:mouseup": "mouseUp($event)", "document:keydown.enter": "handleKeyboardEvent($event)" } }, ngImport: i0, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input type=\"text\" class=\"form-control input-block mb-3\" id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\" />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{\n profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\"\n (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a class=\"mt-2 btn btn-secondary btn-sm float-right\" href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\" role=\"button\">\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button type=\"button\" class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\" (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\" role=\"button\">\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' |\n translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\">\n @for (fixture of fixturePool; track fixture) {\n <div class=\"list-group-item\" [class.active]=\"fixture == selectedFixture\" (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\">\n <div class=\"row\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span\n class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span>{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\"\n (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track $index; let i = $index) {\n <div class=\"dmx-channel\" [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\" [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\" (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\" [attr.data-index]=\"i\" popover=\"{{ i + 1 }}\" placement=\"top\"\n triggers=\"mouseenter:mouseleave\">\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\"\n [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small\n [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' |\n translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\"\n id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select class=\"custom-select\" [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\">\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select class=\"custom-select\" [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\">\n @for (channel of dmxChannels; track $index; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"], dependencies: [{ kind: "directive", type: i3$2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i3$2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3$2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i11.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "directive", type: SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }, { kind: "pipe", type: ArraySortPipe, name: "sort" }] }); }
5527
5642
  }
5528
5643
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FixturePoolComponent, decorators: [{
5529
5644
  type: Component,
5530
- args: [{ selector: 'lib-app-fixture-pool', standalone: false, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input\n type=\"text\"\n class=\"form-control input-block mb-3\"\n id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\"\n />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{ profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a\n class=\"mt-2 btn btn-secondary btn-sm float-right\"\n href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\"\n role=\"button\"\n >\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button\n type=\"button\"\n class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\"\n (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\"\n role=\"button\"\n >\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' | translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <!-- TODO sortablejs breaks sortable lists in base designer view, as soon as it disappears -->\n <!-- Reproduce: select a fixture, deselect a fixture, open pool, close pool without changes, fixture is \"half\"-selected again -->\n <!-- <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\"> -->\n <div class=\"list-group list-group-flush\">\n @for (fixture of fixturePool; track fixture) {\n <div\n class=\"list-group-item\"\n [class.active]=\"fixture == selectedFixture\"\n (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\"\n >\n <div class=\"row\">\n <!-- <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div> -->\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span\n >{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track $index; let i = $index) {\n <div\n class=\"dmx-channel\"\n [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\"\n [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\"\n (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\"\n [attr.data-index]=\"i\"\n popover=\"{{ i + 1 }}\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n >\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\" [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' | translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\" id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\"\n >\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\"\n >\n @for (channel of dmxChannels; track $index; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>\n", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"] }]
5645
+ args: [{ selector: 'lib-app-fixture-pool', standalone: false, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input type=\"text\" class=\"form-control input-block mb-3\" id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\" />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{\n profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\"\n (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a class=\"mt-2 btn btn-secondary btn-sm float-right\" href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\" role=\"button\">\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button type=\"button\" class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\" (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\" role=\"button\">\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' |\n translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\">\n @for (fixture of fixturePool; track fixture) {\n <div class=\"list-group-item\" [class.active]=\"fixture == selectedFixture\" (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\">\n <div class=\"row\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span\n class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span>{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\"\n (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track $index; let i = $index) {\n <div class=\"dmx-channel\" [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\" [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\" (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\" [attr.data-index]=\"i\" popover=\"{{ i + 1 }}\" placement=\"top\"\n triggers=\"mouseenter:mouseleave\">\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\"\n [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small\n [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' |\n translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\"\n id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select class=\"custom-select\" [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\">\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select class=\"custom-select\" [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\">\n @for (channel of dmxChannels; track $index; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"] }]
5531
5646
  }], ctorParameters: () => [{ type: i1$1.BsModalRef }, { type: FixtureService }, { type: UuidService }, { type: ProjectService }, { type: PreviewService }, { type: i4.TranslateService }, { type: i3$1.ToastrService }, { type: PresetService }, { type: ConfigService }, { type: i1$1.BsModalService }], propDecorators: { mouseUp: [{
5532
5647
  type: HostListener,
5533
5648
  args: ['window:mouseup', ['$event']]
@@ -6376,7 +6491,7 @@ class SceneComponent {
6376
6491
  });
6377
6492
  }
6378
6493
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SceneComponent, deps: [{ token: SceneService }, { token: PresetService }, { token: ProjectService }, { token: i1$1.BsModalService }, { token: IntroService }], target: i0.ɵɵFactoryTarget.Component }); }
6379
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SceneComponent, isStandalone: false, selector: "lib-app-scene", ngImport: i0, template: "<div class=\"card border-secondary panel h-100\" [class.card-intro-active]=\"introService.showStep('scenes')\">\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.scene.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a\n href=\"#\"\n class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\"\n [class.text-primary]=\"sceneService.multipleSelection == true\"\n (click)=\"sceneService.multipleSelection = !sceneService.multipleSelection; (false)\"\n ><i class=\"fa fa-object-group fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\" (click)=\"removeScene(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\" (click)=\"sceneService.addScene(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n <div class=\"card-body border-secondary p-0\">\n <!-- List of scenes -->\n <div class=\"list-group\" [sortablejs]=\"projectService.project.scenes\">\n @for (scene of projectService.project.scenes; track scene; let i = $index) {\n <div\n class=\"list-group-item\"\n [class.active-light]=\"projectService.project.previewPreset && sceneService.sceneIsSelected(scene)\"\n [class.active]=\"!projectService.project.previewPreset && sceneService.sceneIsSelected(scene)\"\n >\n <div class=\"row d-flex\" (click)=\"selectScene($event, i)\" style=\"cursor: pointer\">\n <div class=\"d-none d-md-block col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"my-auto\">\n {{ scene.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <svg class=\"my-auto\" height=\"20\" width=\"20\">\n <circle cx=\"10\" cy=\"10\" r=\"9\" stroke=\"white\" stroke-width=\"1\" [attr.fill]=\"scene.color\" />\n </svg>\n </div>\n <div class=\"d-none d-md-flex my-auto mr-2\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(scene); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i7.SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions", "sortablejsCloneFunction"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
6494
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: SceneComponent, isStandalone: false, selector: "lib-app-scene", ngImport: i0, template: "<div class=\"card border-secondary panel h-100\" [class.card-intro-active]=\"introService.showStep('scenes')\">\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.scene.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a\n href=\"#\"\n class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\"\n [class.text-primary]=\"sceneService.multipleSelection == true\"\n (click)=\"sceneService.multipleSelection = !sceneService.multipleSelection; (false)\"\n ><i class=\"fa fa-object-group fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\" (click)=\"removeScene(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"d-none d-md-inline-block btn btn-secondary m-0 p-0\" (click)=\"sceneService.addScene(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n <div class=\"card-body border-secondary p-0\">\n <!-- List of scenes -->\n <div class=\"list-group\" [sortablejs]=\"projectService.project.scenes\">\n @for (scene of projectService.project.scenes; track scene; let i = $index) {\n <div\n class=\"list-group-item\"\n [class.active-light]=\"projectService.project.previewPreset && sceneService.sceneIsSelected(scene)\"\n [class.active]=\"!projectService.project.previewPreset && sceneService.sceneIsSelected(scene)\"\n >\n <div class=\"row d-flex\" (click)=\"selectScene($event, i)\" style=\"cursor: pointer\">\n <div class=\"d-none d-md-block col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"my-auto\">\n {{ scene.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <svg class=\"my-auto\" height=\"20\" width=\"20\">\n <circle cx=\"10\" cy=\"10\" r=\"9\" stroke=\"white\" stroke-width=\"1\" [attr.fill]=\"scene.color\" />\n </svg>\n </div>\n <div class=\"d-none d-md-flex my-auto mr-2\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(scene); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
6380
6495
  }
6381
6496
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: SceneComponent, decorators: [{
6382
6497
  type: Component,
@@ -6435,7 +6550,7 @@ class FixtureComponent {
6435
6550
  this.fixturePoolService.open();
6436
6551
  }
6437
6552
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FixtureComponent, deps: [{ token: ProjectService }, { token: PresetService }, { token: FixturePoolService }, { token: FixtureService }, { token: IntroService }], target: i0.ɵɵFactoryTarget.Component }); }
6438
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FixtureComponent, isStandalone: false, selector: "lib-app-fixture", ngImport: i0, template: "<div class=\"card border-secondary h-100 panel\" [class.card-intro-active]=\"introService.showStep('fixtures')\">\n <div class=\"card-header d-flex\">\n <div>Fixtures</div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"selectNone(); (false)\"\n ><i class=\"fa fa-square-o fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"selectAll(); (false)\"\n ><i class=\"fa fa-check-square-o fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"openFixturePool(); (false)\"\n ><i class=\"fa fa-cog fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of fixtures -->\n @if (presetService.selectedPreset) {\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presetFixtures\">\n @for (presetFixture of projectService.project.presetFixtures; track presetFixture) {\n <div class=\"list-group-item\" [class.inactive-list-item]=\"!fixtureIsSelected(presetFixture)\">\n <div class=\"row d-flex\" (click)=\"selectFixture($event, presetFixture)\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"active\" [ngModel]=\"fixtureIsSelected(presetFixture)\" />\n </div>\n <div>\n <span\n class=\"icon-{{\n fixtureService.getFixtureIconClass(\n fixtureService.getProfileByUuid(fixtureService.getFixtureByUuid(presetFixture.fixtureUuid).profileUuid)\n )\n }} mr-1\"\n ></span>\n {{ fixtureName(presetFixture) }}\n </div>\n </div>\n </div>\n }\n </div>\n } @if (projectService.project.presetFixtures.length == 0) {\n <div class=\"w-100 h-100 d-flex p-3 text-center\">\n <a href=\"#\" class=\"m-auto\" (click)=\"openFixturePool(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i> {{ 'designer.fixture.no-fixtures' | translate }}</a\n >\n </div>\n }\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i3$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions", "sortablejsCloneFunction"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
6553
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: FixtureComponent, isStandalone: false, selector: "lib-app-fixture", ngImport: i0, template: "<div class=\"card border-secondary h-100 panel\" [class.card-intro-active]=\"introService.showStep('fixtures')\">\n <div class=\"card-header d-flex\">\n <div>Fixtures</div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"selectNone(); (false)\"\n ><i class=\"fa fa-square-o fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"selectAll(); (false)\"\n ><i class=\"fa fa-check-square-o fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"openFixturePool(); (false)\"\n ><i class=\"fa fa-cog fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of fixtures -->\n @if (presetService.selectedPreset) {\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presetFixtures\">\n @for (presetFixture of projectService.project.presetFixtures; track presetFixture) {\n <div class=\"list-group-item\" [class.inactive-list-item]=\"!fixtureIsSelected(presetFixture)\">\n <div class=\"row d-flex\" (click)=\"selectFixture($event, presetFixture)\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"active\" [ngModel]=\"fixtureIsSelected(presetFixture)\" />\n </div>\n <div>\n <span\n class=\"icon-{{\n fixtureService.getFixtureIconClass(\n fixtureService.getProfileByUuid(fixtureService.getFixtureByUuid(presetFixture.fixtureUuid).profileUuid)\n )\n }} mr-1\"\n ></span>\n {{ fixtureName(presetFixture) }}\n </div>\n </div>\n </div>\n }\n </div>\n } @if (projectService.project.presetFixtures.length == 0) {\n <div class=\"w-100 h-100 d-flex p-3 text-center\">\n <a href=\"#\" class=\"m-auto\" (click)=\"openFixturePool(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i> {{ 'designer.fixture.no-fixtures' | translate }}</a\n >\n </div>\n }\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i3$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
6439
6554
  }
6440
6555
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: FixtureComponent, decorators: [{
6441
6556
  type: Component,
@@ -7740,7 +7855,7 @@ class PresetComponent {
7740
7855
  });
7741
7856
  }
7742
7857
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PresetComponent, deps: [{ token: PresetService }, { token: SceneService }, { token: ProjectService }, { token: IntroService }, { token: i1$1.BsModalService }], target: i0.ɵɵFactoryTarget.Component }); }
7743
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: PresetComponent, isStandalone: false, selector: "lib-app-preset", viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true }], ngImport: i0, template: "<div\n class=\"card border-secondary h-100 panel card-intro-preset card-intro-active\"\n [class.card-intro-active]=\"introService.showStep('presets')\"\n>\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.preset.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"removePreset(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"addPreset(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of presets -->\n <!-- <tree-root #tree [nodes]=\"treeNodes\" [options]=\"treeOptions\" (activate)=\"onActivate($event)\">\n <ng-template #treeNodeTemplate let-node let-index=\"index\">\n <span>{{ node.data.name }}</span>\n </ng-template>\n </tree-root> -->\n\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presets\">\n @for (item of projectService.project.presets; track item; let i = $index) {\n <div\n class=\"list-group-item\"\n (click)=\"selectPreset(i)\"\n [class.active-light]=\"!projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.active]=\"projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.inactive-list-item]=\"!sceneService.presetIsSelected(item)\"\n >\n <div class=\"row d-flex\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n [disabled]=\"!enableCheckbox()\"\n class=\"form-check-input\"\n id=\"active\"\n [ngModel]=\"sceneService.presetIsSelected(item)\"\n (ngModelChange)=\"activatePreset($event, i)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n <div>\n {{ item.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(item); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i3$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i7.SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions", "sortablejsCloneFunction"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
7858
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: PresetComponent, isStandalone: false, selector: "lib-app-preset", viewQueries: [{ propertyName: "tree", first: true, predicate: ["tree"], descendants: true }], ngImport: i0, template: "<div\n class=\"card border-secondary h-100 panel card-intro-preset card-intro-active\"\n [class.card-intro-active]=\"introService.showStep('presets')\"\n>\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.preset.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"removePreset(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"addPreset(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of presets -->\n <!-- <tree-root #tree [nodes]=\"treeNodes\" [options]=\"treeOptions\" (activate)=\"onActivate($event)\">\n <ng-template #treeNodeTemplate let-node let-index=\"index\">\n <span>{{ node.data.name }}</span>\n </ng-template>\n </tree-root> -->\n\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presets\">\n @for (item of projectService.project.presets; track item; let i = $index) {\n <div\n class=\"list-group-item\"\n (click)=\"selectPreset(i)\"\n [class.active-light]=\"!projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.active]=\"projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.inactive-list-item]=\"!sceneService.presetIsSelected(item)\"\n >\n <div class=\"row d-flex\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n [disabled]=\"!enableCheckbox()\"\n class=\"form-check-input\"\n id=\"active\"\n [ngModel]=\"sceneService.presetIsSelected(item)\"\n (ngModelChange)=\"activatePreset($event, i)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n <div>\n {{ item.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(item); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "directive", type: i3$2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i3$2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3$2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: SortablejsDirective, selector: "[sortablejs]", inputs: ["sortablejs", "sortablejsContainer", "sortablejsOptions"], outputs: ["sortablejsInit"] }, { kind: "pipe", type: i4.TranslatePipe, name: "translate" }] }); }
7744
7859
  }
7745
7860
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PresetComponent, decorators: [{
7746
7861
  type: Component,
@@ -8425,7 +8540,8 @@ class DesignerModule {
8425
8540
  SceneSettingsComponent,
8426
8541
  ProjectSaveComponent,
8427
8542
  FixturePoolCreateFromFileComponent,
8428
- DropzoneComponent], imports: [i3.RouterModule, BrowserModule,
8543
+ DropzoneComponent,
8544
+ SortablejsDirective], imports: [i3.RouterModule, BrowserModule,
8429
8545
  BrowserAnimationsModule,
8430
8546
  FormsModule,
8431
8547
  NgxBootstrapSliderModule,
@@ -8433,7 +8549,6 @@ class DesignerModule {
8433
8549
  AccordionModule,
8434
8550
  PopoverModule,
8435
8551
  TypeaheadModule,
8436
- SortablejsModule,
8437
8552
  DropzoneModule, i3$1.ToastrModule, TreeModule], exports: [DesignerComponent] }); }
8438
8553
  static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: DesignerModule, providers: [provideHttpClient(withInterceptorsFromDi())], imports: [RouterModule.forRoot([], {}),
8439
8554
  BrowserModule,
@@ -8444,7 +8559,6 @@ class DesignerModule {
8444
8559
  AccordionModule,
8445
8560
  PopoverModule,
8446
8561
  TypeaheadModule,
8447
- SortablejsModule,
8448
8562
  DropzoneModule,
8449
8563
  ToastrModule.forRoot({
8450
8564
  newestOnTop: true,
@@ -8493,6 +8607,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8493
8607
  ProjectSaveComponent,
8494
8608
  FixturePoolCreateFromFileComponent,
8495
8609
  DropzoneComponent,
8610
+ SortablejsDirective,
8496
8611
  ],
8497
8612
  exports: [DesignerComponent],
8498
8613
  imports: [
@@ -8505,7 +8620,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
8505
8620
  AccordionModule,
8506
8621
  PopoverModule,
8507
8622
  TypeaheadModule,
8508
- SortablejsModule,
8509
8623
  DropzoneModule,
8510
8624
  ToastrModule.forRoot({
8511
8625
  newestOnTop: true,