croco-html 2.15.0 → 2.16.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.
@@ -0,0 +1,24 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { BehaviorSubject } from "rxjs";
3
+ import * as i0 from "@angular/core";
4
+ export class ScreenWidthService {
5
+ constructor() {
6
+ this.screenWidth = new BehaviorSubject(window.innerWidth);
7
+ window.addEventListener('resize', this.onResize.bind(this));
8
+ }
9
+ onResize(event) {
10
+ this.screenWidth.next(window.innerWidth);
11
+ }
12
+ getScreenWidth() {
13
+ return this.screenWidth.asObservable();
14
+ }
15
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
16
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, providedIn: 'root' }); }
17
+ }
18
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, decorators: [{
19
+ type: Injectable,
20
+ args: [{
21
+ providedIn: 'root'
22
+ }]
23
+ }], ctorParameters: () => [] });
24
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2NyZWVuLXdpZHRoLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9jcm9jby1odG1sL3NyYy9saWIvc2VydmljZXMvc2NyZWVuLXdpZHRoLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQUMsZUFBZSxFQUFhLE1BQU0sTUFBTSxDQUFDOztBQUtqRCxNQUFNLE9BQU8sa0JBQWtCO0lBSTdCO1FBRlEsZ0JBQVcsR0FBRyxJQUFJLGVBQWUsQ0FBUyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7UUFHbkUsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO0lBQzlELENBQUM7SUFFTyxRQUFRLENBQUMsS0FBWTtRQUMzQixJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVELGNBQWM7UUFDWixPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxFQUFFLENBQUE7SUFDeEMsQ0FBQzs4R0FkVSxrQkFBa0I7a0hBQWxCLGtCQUFrQixjQUZqQixNQUFNOzsyRkFFUCxrQkFBa0I7a0JBSDlCLFVBQVU7bUJBQUM7b0JBQ1YsVUFBVSxFQUFFLE1BQU07aUJBQ25CIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtCZWhhdmlvclN1YmplY3QsIE9ic2VydmFibGV9IGZyb20gXCJyeGpzXCI7XG5cbkBJbmplY3RhYmxlKHtcbiAgcHJvdmlkZWRJbjogJ3Jvb3QnXG59KVxuZXhwb3J0IGNsYXNzIFNjcmVlbldpZHRoU2VydmljZSB7XG5cbiAgcHJpdmF0ZSBzY3JlZW5XaWR0aCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8bnVtYmVyPih3aW5kb3cuaW5uZXJXaWR0aCk7XG5cbiAgY29uc3RydWN0b3IoKSB7XG4gICAgd2luZG93LmFkZEV2ZW50TGlzdGVuZXIoJ3Jlc2l6ZScsIHRoaXMub25SZXNpemUuYmluZCh0aGlzKSk7XG4gIH1cblxuICBwcml2YXRlIG9uUmVzaXplKGV2ZW50OiBFdmVudCkge1xuICAgIHRoaXMuc2NyZWVuV2lkdGgubmV4dCh3aW5kb3cuaW5uZXJXaWR0aCk7XG4gIH1cblxuICBnZXRTY3JlZW5XaWR0aCgpOiBPYnNlcnZhYmxlPG51bWJlcj4ge1xuICAgIHJldHVybiB0aGlzLnNjcmVlbldpZHRoLmFzT2JzZXJ2YWJsZSgpXG4gIH1cbn1cbiJdfQ==
@@ -22,7 +22,11 @@ import { NgSelectModule } from '@ng-select/ng-select';
22
22
  import * as i29 from '@angular/material/button-toggle';
23
23
  import { MatButtonToggleGroup, MatButtonToggle, MatButtonToggleModule } from '@angular/material/button-toggle';
24
24
  import * as i28 from '@angular/cdk/drag-drop';
25
- import { moveItemInArray, CdkDropList, CdkDrag, CdkDragHandle, DragDropModule } from '@angular/cdk/drag-drop';
25
+ import { CdkDragHandle, moveItemInArray, CdkDropList, CdkDrag, DragDropModule } from '@angular/cdk/drag-drop';
26
+ import { NgStyle, CommonModule } from '@angular/common';
27
+ import * as i22 from '@angular/material/slide-toggle';
28
+ import { MatSlideToggle, MatSlideToggleModule } from '@angular/material/slide-toggle';
29
+ import { BehaviorSubject, Subject, takeUntil } from 'rxjs';
26
30
  import * as i24 from '@angular/material/core';
27
31
  import { MatOption, MatNativeDateModule } from '@angular/material/core';
28
32
  import * as i11 from '@angular/material/select';
@@ -34,7 +38,6 @@ import { MatTabGroup, MatTab, MatTabsModule } from '@angular/material/tabs';
34
38
  import * as i1$5 from 'ngx-clipboard';
35
39
  import * as i2$3 from '@angular/material/snack-bar';
36
40
  import { MatSnackBarModule } from '@angular/material/snack-bar';
37
- import { CommonModule } from '@angular/common';
38
41
  import * as i12 from '@angular/material/tooltip';
39
42
  import { MatTooltipModule } from '@angular/material/tooltip';
40
43
  import * as i13 from '@angular/material/checkbox';
@@ -61,173 +64,11 @@ import * as i6 from '@angular/material/progress-bar';
61
64
  import { MatProgressBarModule } from '@angular/material/progress-bar';
62
65
  import * as i26 from '@angular/material/sidenav';
63
66
  import { MatSidenavModule } from '@angular/material/sidenav';
64
- import * as i22 from '@angular/material/slide-toggle';
65
- import { MatSlideToggleModule } from '@angular/material/slide-toggle';
66
67
  import * as i23 from '@angular/material/tree';
67
68
  import { MatTreeModule } from '@angular/material/tree';
68
69
  import * as i1$6 from '@angular/material/badge';
69
70
  import { MatBadgeModule } from '@angular/material/badge';
70
71
 
71
- class FileImageTagDataConsts {
72
- static { this.TagName = "file-image"; }
73
- static { this.FileIdAttrName = "file-id"; }
74
- }
75
- class ImageMethods {
76
- static buildUrl(fileId, sizeType, options) {
77
- if (fileId === null || fileId === undefined) {
78
- return null;
79
- }
80
- return options.publicImageResizedUrlFormat
81
- .replace("{sizeType}", sizeType)
82
- .replace("{fileId}", fileId.toString());
83
- }
84
- static buildSmallUrl(fileId, options) {
85
- return ImageMethods.buildUrl(fileId, "Small", options);
86
- }
87
- static buildMediumUrl(fileId, options) {
88
- return ImageMethods.buildUrl(fileId, "Medium", options);
89
- }
90
- static ExtractImage(elem, options) {
91
- let fileId = +elem.getAttribute(FileImageTagDataConsts.FileIdAttrName);
92
- let src = ImageMethods.buildMediumUrl(fileId, options);
93
- return {
94
- type: FileImageTagDataConsts.TagName,
95
- data: {
96
- src,
97
- fileId: fileId,
98
- }
99
- };
100
- }
101
- }
102
-
103
- class FileUploadService {
104
- constructor(_httpClient, baseUrl) {
105
- this._httpClient = _httpClient;
106
- this.baseUrl = baseUrl;
107
- }
108
- postFiles(files, createLocalCopiesNow = false) {
109
- const formData = new FormData();
110
- for (let i = 0; i < files.length; i++) {
111
- var fileToUpload = files.item(i);
112
- formData.append(`fileKey${i}`, fileToUpload, fileToUpload?.name);
113
- }
114
- return this.postFilesInner(formData, createLocalCopiesNow);
115
- }
116
- postFilesInner(formData, createLocalCopiesNow = false, withProgress = false) {
117
- let endpoint = createLocalCopiesNow
118
- ? this.baseUrl + 'api/files/upload/now/with-handlers'
119
- : this.baseUrl + 'Api/Files/UploadFiles';
120
- return this._httpClient.post(endpoint, formData, withProgress ? { reportProgress: true, observe: 'events' } : undefined);
121
- }
122
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, deps: [{ token: i1.HttpClient }, { token: 'BASE_URL' }], target: i0.ɵɵFactoryTarget.Injectable }); }
123
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, providedIn: 'root' }); }
124
- }
125
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, decorators: [{
126
- type: Injectable,
127
- args: [{ providedIn: 'root' }]
128
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
129
- type: Inject,
130
- args: ['BASE_URL']
131
- }] }] });
132
-
133
- class UploadFilesBtnComponent {
134
- constructor(_fileUploadService) {
135
- this._fileUploadService = _fileUploadService;
136
- this.extAccepts = "*/*";
137
- this.isMultiple = true;
138
- this.btnText = "Загрузить файлы";
139
- this.createLocalCopiesNow = true;
140
- this.hidden = false;
141
- this.postFilesStarted = new EventEmitter();
142
- this.onFilesUploaded = new EventEmitter();
143
- }
144
- handleFileInput(files) {
145
- this.postFilesStarted.emit({
146
- filesCount: files.length,
147
- createLocalCopiesNow: this.createLocalCopiesNow
148
- });
149
- this._fileUploadService.postFiles(files, this.createLocalCopiesNow).subscribe(data => {
150
- this.onFilesUploaded.emit(data);
151
- });
152
- }
153
- clickFileInput() {
154
- this.fileInput.nativeElement.click();
155
- }
156
- ngOnInit() {
157
- }
158
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: UploadFilesBtnComponent, deps: [{ token: FileUploadService }], target: i0.ɵɵFactoryTarget.Component }); }
159
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: UploadFilesBtnComponent, isStandalone: true, selector: "croco-app-upload-files-btn", inputs: { extAccepts: "extAccepts", isMultiple: "isMultiple", btnText: "btnText", createLocalCopiesNow: "createLocalCopiesNow", hidden: "hidden" }, outputs: { postFilesStarted: "postFilesStarted", onFilesUploaded: "onFilesUploaded" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["filesInput"], descendants: true }], ngImport: i0, template: "<button [hidden]=\"hidden\" mat-raised-button color=\"primary\" (click)=\"filesInput.click()\">{{btnText}}</button>\n<input [hidden]=\"true\" [accept]=\"extAccepts\" [multiple]=\"isMultiple\" type=\"file\" #filesInput (change)=\"handleFileInput($event.target.files)\" />", styles: [""], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
160
- }
161
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: UploadFilesBtnComponent, decorators: [{
162
- type: Component,
163
- args: [{ selector: 'croco-app-upload-files-btn', standalone: true, imports: [MatButton], template: "<button [hidden]=\"hidden\" mat-raised-button color=\"primary\" (click)=\"filesInput.click()\">{{btnText}}</button>\n<input [hidden]=\"true\" [accept]=\"extAccepts\" [multiple]=\"isMultiple\" type=\"file\" #filesInput (change)=\"handleFileInput($event.target.files)\" />" }]
164
- }], ctorParameters: () => [{ type: FileUploadService }], propDecorators: { fileInput: [{
165
- type: ViewChild,
166
- args: ['filesInput']
167
- }], extAccepts: [{
168
- type: Input
169
- }], isMultiple: [{
170
- type: Input
171
- }], btnText: [{
172
- type: Input
173
- }], createLocalCopiesNow: [{
174
- type: Input
175
- }], hidden: [{
176
- type: Input
177
- }], postFilesStarted: [{
178
- type: Output
179
- }], onFilesUploaded: [{
180
- type: Output
181
- }] } });
182
-
183
- class AddFilesBtnComponent {
184
- constructor() {
185
- this.postFilesStarted = new EventEmitter();
186
- this.fileIds = [];
187
- this.filesTagsReady = new EventEmitter();
188
- }
189
- postFilesStartedEventHandler(data) {
190
- this.postFilesStarted.emit(data);
191
- }
192
- filesUploadedHandler(data) {
193
- this.fileIds = data.responseObject;
194
- let fileTags = [];
195
- for (let i = 0; i < this.fileIds.length; i++) {
196
- let fileTag = {
197
- presentOrEdit: true,
198
- tagDescription: {
199
- tag: FileImageTagDataConsts.TagName,
200
- displayValue: "Изображение"
201
- },
202
- attributes: {
203
- [FileImageTagDataConsts.FileIdAttrName]: this.fileIds[i]
204
- },
205
- innerHtml: ""
206
- };
207
- fileTags.push(fileTag);
208
- }
209
- this.filesTagsReady.emit(fileTags);
210
- }
211
- handleClick() {
212
- this.fakeBtn.clickFileInput();
213
- }
214
- ngOnInit() {
215
- }
216
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: AddFilesBtnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
217
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: AddFilesBtnComponent, isStandalone: true, selector: "croco-html-add-files-btn", outputs: { postFilesStarted: "postFilesStarted", filesTagsReady: "filesTagsReady" }, viewQueries: [{ propertyName: "fakeBtn", first: true, predicate: ["fakeBtn"], descendants: true }], ngImport: i0, template: "<div [hidden]=\"true\">\n <croco-app-upload-files-btn #fakeBtn (onFilesUploaded)=\"filesUploadedHandler($event)\"\n [btnText]=\"'\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F'\" [createLocalCopiesNow]=\"true\"\n (postFilesStarted)=\"postFilesStartedEventHandler($event)\" [extAccepts]=\"'image/*'\"></croco-app-upload-files-btn>\n</div>\n\n<div>\n <button class=\"w-100\" (click)=\"handleClick()\" mat-stroked-button>\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F</button>\n</div>", styles: [""], dependencies: [{ kind: "component", type: UploadFilesBtnComponent, selector: "croco-app-upload-files-btn", inputs: ["extAccepts", "isMultiple", "btnText", "createLocalCopiesNow", "hidden"], outputs: ["postFilesStarted", "onFilesUploaded"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
218
- }
219
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: AddFilesBtnComponent, decorators: [{
220
- type: Component,
221
- args: [{ selector: 'croco-html-add-files-btn', standalone: true, imports: [UploadFilesBtnComponent, MatButton], template: "<div [hidden]=\"true\">\n <croco-app-upload-files-btn #fakeBtn (onFilesUploaded)=\"filesUploadedHandler($event)\"\n [btnText]=\"'\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F'\" [createLocalCopiesNow]=\"true\"\n (postFilesStarted)=\"postFilesStartedEventHandler($event)\" [extAccepts]=\"'image/*'\"></croco-app-upload-files-btn>\n</div>\n\n<div>\n <button class=\"w-100\" (click)=\"handleClick()\" mat-stroked-button>\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F</button>\n</div>" }]
222
- }], ctorParameters: () => [], propDecorators: { postFilesStarted: [{
223
- type: Output
224
- }], fakeBtn: [{
225
- type: ViewChild,
226
- args: ["fakeBtn"]
227
- }], filesTagsReady: [{
228
- type: Output
229
- }] } });
230
-
231
72
  class AngularMaterialTableMethods {
232
73
  static getAngularMaterialTableData(columns, rows) {
233
74
  let data = [];
@@ -292,6 +133,75 @@ class AngularMaterialTableMethods {
292
133
  }
293
134
  }
294
135
 
136
+ class FileImageTagDataConsts {
137
+ static { this.TagName = "file-image"; }
138
+ static { this.FileIdAttrName = "file-id"; }
139
+ static { this.ScreenMediaRequest = "screen-media-request"; }
140
+ static { this.DefaultValueForFileImage = "screen-width:1200,max-image-height:300;screen-width:900,max-image-height:200"; }
141
+ static { this.ScreenWidth = 'screen-width'; }
142
+ static { this.MaxImageHeight = 'max-image-height'; }
143
+ }
144
+ class ImageMethods {
145
+ static buildUrl(fileId, sizeType, options) {
146
+ if (fileId === null || fileId === undefined) {
147
+ return null;
148
+ }
149
+ return options.publicImageResizedUrlFormat
150
+ .replace("{sizeType}", sizeType)
151
+ .replace("{fileId}", fileId.toString());
152
+ }
153
+ static buildSmallUrl(fileId, options) {
154
+ return ImageMethods.buildUrl(fileId, "Small", options);
155
+ }
156
+ static buildMediumUrl(fileId, options) {
157
+ return ImageMethods.buildUrl(fileId, "Medium", options);
158
+ }
159
+ static ExtractImage(elem, options) {
160
+ let fileId = +elem.getAttribute(FileImageTagDataConsts.FileIdAttrName);
161
+ let src = ImageMethods.buildMediumUrl(fileId, options);
162
+ return {
163
+ type: FileImageTagDataConsts.TagName,
164
+ data: {
165
+ src,
166
+ fileId: fileId,
167
+ screenMediaRequest: elem.getAttribute(FileImageTagDataConsts.ScreenMediaRequest)
168
+ }
169
+ };
170
+ }
171
+ static { this.mediaRequestStringToArrayParser = (data) => {
172
+ if (!data.length) {
173
+ return [];
174
+ }
175
+ return data.split(';').reduce((requests, currentValue) => {
176
+ requests.push({
177
+ screenWidth: ImageMethods.createMediaRequestValue(currentValue.split(','), FileImageTagDataConsts.ScreenWidth),
178
+ maxImageHeight: ImageMethods.createMediaRequestValue(currentValue.split(','), FileImageTagDataConsts.MaxImageHeight),
179
+ });
180
+ return requests;
181
+ }, []);
182
+ }; }
183
+ static createMediaRequestValue(arr, attribute) {
184
+ return +arr.find(el => el.includes(attribute)).match(/\d+/g).join('');
185
+ }
186
+ static { this.mediaRequestsArrayToStringParser = (data) => {
187
+ if (!data.length) {
188
+ return '';
189
+ }
190
+ return data.map(el => `${FileImageTagDataConsts.ScreenWidth}:${el.screenWidth},${FileImageTagDataConsts.MaxImageHeight}:${el.maxImageHeight}`).join(';');
191
+ }; }
192
+ static { this.screenSizeChanged = (screenSize, requests) => {
193
+ let newSize = null;
194
+ requests
195
+ .sort((a, b) => a.screenWidth > b.screenWidth ? -1 : 1)
196
+ .forEach((el, index) => {
197
+ if (screenSize < +el.screenWidth) {
198
+ newSize = el.maxImageHeight;
199
+ }
200
+ });
201
+ return newSize;
202
+ }; }
203
+ }
204
+
295
205
  var EAlignments;
296
206
  (function (EAlignments) {
297
207
  EAlignments["Left"] = "left";
@@ -698,6 +608,9 @@ class HtmlExtractionMethods {
698
608
 
699
609
  class HtmlRawTagDataConsts {
700
610
  static { this.TagName = "html-raw"; }
611
+ static { this.ScreenWidth = "screen-width"; }
612
+ static { this.MaxImageHeight = "max-image-height"; }
613
+ static { this.MediaRequest = " media-request"; }
701
614
  }
702
615
 
703
616
  class Tags {
@@ -757,12 +670,13 @@ class BodyTagsExtensions {
757
670
  return result;
758
671
  }
759
672
  static imageTagToHtml(imageTag) {
760
- var attrStr = "";
761
- var attrValue = imageTag.attributes[FileImageTagDataConsts.FileIdAttrName];
673
+ let fileIdAttr = "";
674
+ let screenMediaRequestAttr = "";
675
+ let attrValue = imageTag.attributes[FileImageTagDataConsts.FileIdAttrName];
762
676
  if (imageTag.attributes.hasOwnProperty(FileImageTagDataConsts.FileIdAttrName) && attrValue) {
763
- attrStr = `${FileImageTagDataConsts.FileIdAttrName}="${attrValue}"`;
677
+ fileIdAttr = `${FileImageTagDataConsts.FileIdAttrName}="${attrValue}"`;
764
678
  }
765
- return `<${FileImageTagDataConsts.TagName} ${attrStr}></${FileImageTagDataConsts.TagName}>`;
679
+ return `<${FileImageTagDataConsts.TagName} ${fileIdAttr} ${FileImageTagDataConsts.ScreenMediaRequest}="${imageTag.attributes[FileImageTagDataConsts.ScreenMediaRequest]}"></${FileImageTagDataConsts.TagName}>`;
766
680
  }
767
681
  static getBodyTags(html, options) {
768
682
  let result = HtmlExtractionMethods.transformHtmlStringToBlocks(html, options);
@@ -790,6 +704,9 @@ class BodyTagsExtensions {
790
704
  if (fileData.fileId) {
791
705
  attrs[FileImageTagDataConsts.FileIdAttrName] = fileData.fileId;
792
706
  }
707
+ if (fileData.screenMediaRequest) {
708
+ attrs[FileImageTagDataConsts.ScreenMediaRequest] = fileData.screenMediaRequest;
709
+ }
793
710
  return {
794
711
  presentOrEdit: true,
795
712
  tagDescription: {
@@ -895,6 +812,135 @@ class TableBuilder {
895
812
  }
896
813
  }
897
814
 
815
+ class FileUploadService {
816
+ constructor(_httpClient, baseUrl) {
817
+ this._httpClient = _httpClient;
818
+ this.baseUrl = baseUrl;
819
+ }
820
+ postFiles(files, createLocalCopiesNow = false) {
821
+ const formData = new FormData();
822
+ for (let i = 0; i < files.length; i++) {
823
+ var fileToUpload = files.item(i);
824
+ formData.append(`fileKey${i}`, fileToUpload, fileToUpload?.name);
825
+ }
826
+ return this.postFilesInner(formData, createLocalCopiesNow);
827
+ }
828
+ postFilesInner(formData, createLocalCopiesNow = false, withProgress = false) {
829
+ let endpoint = createLocalCopiesNow
830
+ ? this.baseUrl + 'api/files/upload/now/with-handlers'
831
+ : this.baseUrl + 'Api/Files/UploadFiles';
832
+ return this._httpClient.post(endpoint, formData, withProgress ? { reportProgress: true, observe: 'events' } : undefined);
833
+ }
834
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, deps: [{ token: i1.HttpClient }, { token: 'BASE_URL' }], target: i0.ɵɵFactoryTarget.Injectable }); }
835
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, providedIn: 'root' }); }
836
+ }
837
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: FileUploadService, decorators: [{
838
+ type: Injectable,
839
+ args: [{ providedIn: 'root' }]
840
+ }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
841
+ type: Inject,
842
+ args: ['BASE_URL']
843
+ }] }] });
844
+
845
+ class UploadFilesBtnComponent {
846
+ constructor(_fileUploadService) {
847
+ this._fileUploadService = _fileUploadService;
848
+ this.extAccepts = "*/*";
849
+ this.isMultiple = true;
850
+ this.btnText = "Загрузить файлы";
851
+ this.createLocalCopiesNow = true;
852
+ this.hidden = false;
853
+ this.postFilesStarted = new EventEmitter();
854
+ this.onFilesUploaded = new EventEmitter();
855
+ }
856
+ handleFileInput(files) {
857
+ this.postFilesStarted.emit({
858
+ filesCount: files.length,
859
+ createLocalCopiesNow: this.createLocalCopiesNow
860
+ });
861
+ this._fileUploadService.postFiles(files, this.createLocalCopiesNow).subscribe(data => {
862
+ this.onFilesUploaded.emit(data);
863
+ });
864
+ }
865
+ clickFileInput() {
866
+ this.fileInput.nativeElement.click();
867
+ }
868
+ ngOnInit() {
869
+ }
870
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: UploadFilesBtnComponent, deps: [{ token: FileUploadService }], target: i0.ɵɵFactoryTarget.Component }); }
871
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: UploadFilesBtnComponent, isStandalone: true, selector: "croco-app-upload-files-btn", inputs: { extAccepts: "extAccepts", isMultiple: "isMultiple", btnText: "btnText", createLocalCopiesNow: "createLocalCopiesNow", hidden: "hidden" }, outputs: { postFilesStarted: "postFilesStarted", onFilesUploaded: "onFilesUploaded" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["filesInput"], descendants: true }], ngImport: i0, template: "<button [hidden]=\"hidden\" mat-raised-button color=\"primary\" (click)=\"filesInput.click()\">{{btnText}}</button>\n<input [hidden]=\"true\" [accept]=\"extAccepts\" [multiple]=\"isMultiple\" type=\"file\" #filesInput (change)=\"handleFileInput($event.target.files)\" />", styles: [""], dependencies: [{ kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
872
+ }
873
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: UploadFilesBtnComponent, decorators: [{
874
+ type: Component,
875
+ args: [{ selector: 'croco-app-upload-files-btn', standalone: true, imports: [MatButton], template: "<button [hidden]=\"hidden\" mat-raised-button color=\"primary\" (click)=\"filesInput.click()\">{{btnText}}</button>\n<input [hidden]=\"true\" [accept]=\"extAccepts\" [multiple]=\"isMultiple\" type=\"file\" #filesInput (change)=\"handleFileInput($event.target.files)\" />" }]
876
+ }], ctorParameters: () => [{ type: FileUploadService }], propDecorators: { fileInput: [{
877
+ type: ViewChild,
878
+ args: ['filesInput']
879
+ }], extAccepts: [{
880
+ type: Input
881
+ }], isMultiple: [{
882
+ type: Input
883
+ }], btnText: [{
884
+ type: Input
885
+ }], createLocalCopiesNow: [{
886
+ type: Input
887
+ }], hidden: [{
888
+ type: Input
889
+ }], postFilesStarted: [{
890
+ type: Output
891
+ }], onFilesUploaded: [{
892
+ type: Output
893
+ }] } });
894
+
895
+ class AddFilesBtnComponent {
896
+ constructor() {
897
+ this.postFilesStarted = new EventEmitter();
898
+ this.fileIds = [];
899
+ this.filesTagsReady = new EventEmitter();
900
+ }
901
+ postFilesStartedEventHandler(data) {
902
+ this.postFilesStarted.emit(data);
903
+ }
904
+ filesUploadedHandler(data) {
905
+ this.fileIds = data.responseObject;
906
+ let fileTags = [];
907
+ for (let i = 0; i < this.fileIds.length; i++) {
908
+ let fileTag = {
909
+ presentOrEdit: true,
910
+ tagDescription: {
911
+ tag: FileImageTagDataConsts.TagName,
912
+ displayValue: "Изображение"
913
+ },
914
+ attributes: {
915
+ [FileImageTagDataConsts.FileIdAttrName]: this.fileIds[i],
916
+ [FileImageTagDataConsts.ScreenMediaRequest]: FileImageTagDataConsts.DefaultValueForFileImage
917
+ },
918
+ innerHtml: ""
919
+ };
920
+ fileTags.push(fileTag);
921
+ }
922
+ this.filesTagsReady.emit(fileTags);
923
+ }
924
+ handleClick() {
925
+ this.fakeBtn.clickFileInput();
926
+ }
927
+ ngOnInit() {
928
+ }
929
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: AddFilesBtnComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
930
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.4", type: AddFilesBtnComponent, isStandalone: true, selector: "croco-html-add-files-btn", outputs: { postFilesStarted: "postFilesStarted", filesTagsReady: "filesTagsReady" }, viewQueries: [{ propertyName: "fakeBtn", first: true, predicate: ["fakeBtn"], descendants: true }], ngImport: i0, template: "<div [hidden]=\"true\">\n <croco-app-upload-files-btn #fakeBtn (onFilesUploaded)=\"filesUploadedHandler($event)\"\n [btnText]=\"'\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F'\" [createLocalCopiesNow]=\"true\"\n (postFilesStarted)=\"postFilesStartedEventHandler($event)\" [extAccepts]=\"'image/*'\"></croco-app-upload-files-btn>\n</div>\n\n<div>\n <button class=\"w-100\" (click)=\"handleClick()\" mat-stroked-button>\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F</button>\n</div>", styles: [""], dependencies: [{ kind: "component", type: UploadFilesBtnComponent, selector: "croco-app-upload-files-btn", inputs: ["extAccepts", "isMultiple", "btnText", "createLocalCopiesNow", "hidden"], outputs: ["postFilesStarted", "onFilesUploaded"] }, { kind: "component", type: MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }] }); }
931
+ }
932
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: AddFilesBtnComponent, decorators: [{
933
+ type: Component,
934
+ args: [{ selector: 'croco-html-add-files-btn', standalone: true, imports: [UploadFilesBtnComponent, MatButton], template: "<div [hidden]=\"true\">\n <croco-app-upload-files-btn #fakeBtn (onFilesUploaded)=\"filesUploadedHandler($event)\"\n [btnText]=\"'\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F'\" [createLocalCopiesNow]=\"true\"\n (postFilesStarted)=\"postFilesStartedEventHandler($event)\" [extAccepts]=\"'image/*'\"></croco-app-upload-files-btn>\n</div>\n\n<div>\n <button class=\"w-100\" (click)=\"handleClick()\" mat-stroked-button>\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0438\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u044F</button>\n</div>" }]
935
+ }], ctorParameters: () => [], propDecorators: { postFilesStarted: [{
936
+ type: Output
937
+ }], fakeBtn: [{
938
+ type: ViewChild,
939
+ args: ["fakeBtn"]
940
+ }], filesTagsReady: [{
941
+ type: Output
942
+ }] } });
943
+
898
944
  class YoutubeVideoPlayerComponent {
899
945
  set link(link) {
900
946
  this.safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(link);
@@ -1374,15 +1420,45 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImpor
1374
1420
  type: Output
1375
1421
  }] } });
1376
1422
 
1423
+ class ScreenWidthService {
1424
+ constructor() {
1425
+ this.screenWidth = new BehaviorSubject(window.innerWidth);
1426
+ window.addEventListener('resize', this.onResize.bind(this));
1427
+ }
1428
+ onResize(event) {
1429
+ this.screenWidth.next(window.innerWidth);
1430
+ }
1431
+ getScreenWidth() {
1432
+ return this.screenWidth.asObservable();
1433
+ }
1434
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
1435
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, providedIn: 'root' }); }
1436
+ }
1437
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ScreenWidthService, decorators: [{
1438
+ type: Injectable,
1439
+ args: [{
1440
+ providedIn: 'root'
1441
+ }]
1442
+ }], ctorParameters: () => [] });
1443
+
1377
1444
  class ImageEditorComponent {
1378
1445
  onErrorHandler() {
1379
1446
  this.hasImageError = true;
1380
1447
  }
1381
- constructor(_options) {
1448
+ constructor(_options, screenWidth) {
1382
1449
  this._options = _options;
1383
1450
  this.hasImageError = false;
1384
1451
  this.searchOrEdit = "search";
1452
+ this.requests = [];
1453
+ this.imageMaxHeight = null;
1454
+ this.isShowMediaRequest = false;
1455
+ this.unsubscribe = new Subject();
1385
1456
  this.onTagUpdated = new EventEmitter();
1457
+ screenWidth.getScreenWidth()
1458
+ .pipe(takeUntil(this.unsubscribe))
1459
+ .subscribe(screenWidth => {
1460
+ this.imageMaxHeight = ImageMethods.screenSizeChanged(screenWidth, this.requests);
1461
+ });
1386
1462
  }
1387
1463
  getSrc() {
1388
1464
  return ImageMethods.buildUrl(this.tag.attributes[FileImageTagDataConsts.FileIdAttrName], "Medium", this._options);
@@ -1398,17 +1474,35 @@ class ImageEditorComponent {
1398
1474
  this.hasImageError = false;
1399
1475
  }
1400
1476
  ngOnInit() {
1477
+ this.requests = ImageMethods.mediaRequestStringToArrayParser(this.tag.attributes[FileImageTagDataConsts.ScreenMediaRequest]);
1478
+ }
1479
+ requestChanged() {
1480
+ this.tag.attributes[FileImageTagDataConsts.ScreenMediaRequest] = ImageMethods.mediaRequestsArrayToStringParser(this.requests);
1401
1481
  }
1402
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ImageEditorComponent, deps: [{ token: CrocoHtmlOptionsToken }], target: i0.ɵɵFactoryTarget.Component }); }
1403
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.4", type: ImageEditorComponent, isStandalone: true, selector: "croco-html-image-editor", inputs: { tag: "tag" }, outputs: { onTagUpdated: "onTagUpdated" }, ngImport: i0, template: "<div>\n <div style=\"height: 10px;\">\n </div>\n\n @if (hasImageError) {\n <div class=\"error-block\">\n \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u043E \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u043C\u0443 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443, \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0444\u0430\u0439\u043B \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.\n </div>\n }\n\n @if (hasFileId() && !hasImageError) {\n <div>\n <img class=\"mx-auto d-block img-fluid\" [src]=\"getSrc()\" (error)=\"onErrorHandler()\"/>\n </div>\n }\n\n @if (!hasFileId()) {\n <div>\n <h5>[\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E]</h5>\n </div>\n }\n</div>\n\n@if (!tag.presentOrEdit) {\n <div>\n <div style=\"height: 10px;\"></div>\n <div style=\"overflow-x:auto;\">\n <mat-button-toggle-group [(ngModel)]=\"searchOrEdit\">\n <mat-button-toggle value=\"search\">\n \u0418\u0441\u043A\u0430\u0442\u044C \u0444\u0430\u0439\u043B <mat-icon>search</mat-icon>\n </mat-button-toggle>\n <mat-button-toggle value=\"edit\">\n \u0423\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443 <mat-icon>settings</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"height: 10px;\"></div>\n <div [hidden]=\"searchOrEdit !== 'search'\">\n <croco-html-file-id-select\n [labelText]=\"'\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B'\"\n [(fileId)]=\"tag.attributes['file-id']\"\n (onFileIdChanged)=\"onFileIdChanged($event)\">\n </croco-html-file-id-select>\n </div>\n <div [hidden]=\"searchOrEdit !== 'edit'\">\n <div>\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\n </mat-label>\n <input matInput placeholder=\"\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\" new-autocomplete=\"off\" autocomplete=\"off\"\n type=\"number\"\n [(ngModel)]=\"tag.attributes['file-id']\"\n (ngModelChange)=\"removeImageError()\">\n </mat-form-field>\n </div>\n </div>\n </div>\n}", styles: [".error-block{background-color:#f32323;color:#fff;text-align:center;border-radius:10px;padding:10px}\n"], dependencies: [{ kind: "directive", type: MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.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: i1$4.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: FileIdSelectComponent, selector: "croco-html-file-id-select", inputs: ["labelText", "fileId"], outputs: ["fileId", "onFileIdChanged"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }] }); }
1482
+ addNewMediaRequest() {
1483
+ this.requests.push({
1484
+ screenWidth: 0,
1485
+ maxImageHeight: 0,
1486
+ });
1487
+ }
1488
+ deleteMediaRequest(index) {
1489
+ this.requests.splice(index, 1);
1490
+ this.requestChanged();
1491
+ }
1492
+ ngOnDestroy() {
1493
+ this.unsubscribe.next();
1494
+ this.unsubscribe.complete();
1495
+ }
1496
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ImageEditorComponent, deps: [{ token: CrocoHtmlOptionsToken }, { token: ScreenWidthService }], target: i0.ɵɵFactoryTarget.Component }); }
1497
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.4", type: ImageEditorComponent, isStandalone: true, selector: "croco-html-image-editor", inputs: { tag: "tag" }, outputs: { onTagUpdated: "onTagUpdated" }, ngImport: i0, template: "<div>\n <div style=\"height: 10px;\">\n </div>\n\n @if (hasImageError) {\n <div class=\"error-block\">\n \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u043E \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u043C\u0443 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443, \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0444\u0430\u0439\u043B \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.\n </div>\n }\n\n @if (hasFileId() && !hasImageError) {\n <div>\n <img\n [ngStyle]=\"{ 'max-height': imageMaxHeight ? imageMaxHeight + 'px' : '100%'}\"\n class=\"mx-auto d-block img-fluid\" [src]=\"getSrc()\" (error)=\"onErrorHandler()\" alt=\"photo\"/>\n </div>\n }\n\n @if (!hasFileId()) {\n <div>\n <h5>[\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E]</h5>\n </div>\n }\n\n @if(!tag.presentOrEdit) {\n <mat-slide-toggle style=\"padding: 10px 0\" [(ngModel)]=\"isShowMediaRequest\">\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043C\u0435\u0434\u0438\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B</mat-slide-toggle>\n }\n\n @if(isShowMediaRequest) {\n <div style=\"display: flex; flex-direction: column; gap: 20px\">\n <div class=\"media-request__header\">\n <span>\u041C\u0435\u0434\u0438\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B:</span>\n @if (!tag.presentOrEdit) {\n <button (click)=\"addNewMediaRequest()\" class=\"w-30\" mat-icon-button color=\"primary\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </div>\n @for (request of requests; track $index) {\n <div class=\"media-request__container\">\n @if (tag.presentOrEdit) {\n <div style=\"display: flex; flex-direction: column; gap: 5px\">\n <span class=\"w-100\">\u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B: {{request.screenWidth}}</span>\n <span class=\"w-100\">\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430: {{request.maxImageHeight}}</span>\n </div>\n }\n\n @if (!tag.presentOrEdit) {\n <div style=\"width: 100%\">\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B\n </mat-label>\n <input matInput placeholder=\"\u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B\"\n autocomplete=\"off\"\n [(ngModel)]=\"request.screenWidth\"\n (ngModelChange)=\"requestChanged()\">\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430\n </mat-label>\n <input matInput placeholder=\" \u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430\"\n autocomplete=\"off\"\n [(ngModel)]=\"request.maxImageHeight\"\n (ngModelChange)=\"requestChanged()\">\n </mat-form-field>\n </div>\n\n <button (click)=\"deleteMediaRequest($index)\" class=\"w-30\" mat-icon-button color=\"warn\">\n <mat-icon>delete</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n\n@if (!tag.presentOrEdit) {\n <div>\n <div style=\"height: 10px;\"></div>\n <div style=\"overflow-x:auto;\">\n <mat-button-toggle-group [(ngModel)]=\"searchOrEdit\">\n <mat-button-toggle value=\"search\">\n \u0418\u0441\u043A\u0430\u0442\u044C \u0444\u0430\u0439\u043B <mat-icon>search</mat-icon>\n </mat-button-toggle>\n <mat-button-toggle value=\"edit\">\n \u0423\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443 <mat-icon>settings</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"height: 10px;\"></div>\n <div [hidden]=\"searchOrEdit !== 'search'\">\n <croco-html-file-id-select\n [labelText]=\"'\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B'\"\n [(fileId)]=\"tag.attributes['file-id']\"\n (onFileIdChanged)=\"onFileIdChanged($event)\">\n </croco-html-file-id-select>\n </div>\n <div [hidden]=\"searchOrEdit !== 'edit'\">\n <div>\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\n </mat-label>\n <input matInput placeholder=\"\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\" new-autocomplete=\"off\" autocomplete=\"off\"\n type=\"number\"\n [(ngModel)]=\"tag.attributes['file-id']\"\n (ngModelChange)=\"removeImageError()\">\n </mat-form-field>\n </div>\n </div>\n </div>\n}\n", styles: [".error-block{background-color:#f32323;color:#fff;text-align:center;border-radius:10px;padding:10px}.media-request__header{align-items:center;display:flex;width:100%;justify-content:space-between}.media-request__container{display:flex;align-items:center;border-bottom:1px solid rgba(128,128,128,.7);padding-bottom:10px}\n"], dependencies: [{ kind: "directive", type: MatButtonToggleGroup, selector: "mat-button-toggle-group", inputs: ["appearance", "name", "vertical", "value", "multiple", "disabled", "hideSingleSelectionIndicator", "hideMultipleSelectionIndicator"], outputs: ["valueChange", "change"], exportAs: ["matButtonToggleGroup"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$4.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: i1$4.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1$4.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$4.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: MatButtonToggle, selector: "mat-button-toggle", inputs: ["aria-label", "aria-labelledby", "id", "name", "value", "tabIndex", "disableRipple", "appearance", "checked", "disabled"], outputs: ["change"], exportAs: ["matButtonToggle"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: FileIdSelectComponent, selector: "croco-html-file-id-select", inputs: ["labelText", "fileId"], outputs: ["fileId", "onFileIdChanged"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: MatIconButton, selector: "button[mat-icon-button]", exportAs: ["matButton"] }, { kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }] }); }
1404
1498
  }
1405
1499
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.4", ngImport: i0, type: ImageEditorComponent, decorators: [{
1406
1500
  type: Component,
1407
- args: [{ selector: 'croco-html-image-editor', standalone: true, imports: [MatButtonToggleGroup, FormsModule, MatButtonToggle, MatIcon, FileIdSelectComponent, MatFormField, MatLabel, MatInput], template: "<div>\n <div style=\"height: 10px;\">\n </div>\n\n @if (hasImageError) {\n <div class=\"error-block\">\n \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u043E \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u043C\u0443 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443, \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0444\u0430\u0439\u043B \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.\n </div>\n }\n\n @if (hasFileId() && !hasImageError) {\n <div>\n <img class=\"mx-auto d-block img-fluid\" [src]=\"getSrc()\" (error)=\"onErrorHandler()\"/>\n </div>\n }\n\n @if (!hasFileId()) {\n <div>\n <h5>[\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E]</h5>\n </div>\n }\n</div>\n\n@if (!tag.presentOrEdit) {\n <div>\n <div style=\"height: 10px;\"></div>\n <div style=\"overflow-x:auto;\">\n <mat-button-toggle-group [(ngModel)]=\"searchOrEdit\">\n <mat-button-toggle value=\"search\">\n \u0418\u0441\u043A\u0430\u0442\u044C \u0444\u0430\u0439\u043B <mat-icon>search</mat-icon>\n </mat-button-toggle>\n <mat-button-toggle value=\"edit\">\n \u0423\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443 <mat-icon>settings</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"height: 10px;\"></div>\n <div [hidden]=\"searchOrEdit !== 'search'\">\n <croco-html-file-id-select\n [labelText]=\"'\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B'\"\n [(fileId)]=\"tag.attributes['file-id']\"\n (onFileIdChanged)=\"onFileIdChanged($event)\">\n </croco-html-file-id-select>\n </div>\n <div [hidden]=\"searchOrEdit !== 'edit'\">\n <div>\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\n </mat-label>\n <input matInput placeholder=\"\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\" new-autocomplete=\"off\" autocomplete=\"off\"\n type=\"number\"\n [(ngModel)]=\"tag.attributes['file-id']\"\n (ngModelChange)=\"removeImageError()\">\n </mat-form-field>\n </div>\n </div>\n </div>\n}", styles: [".error-block{background-color:#f32323;color:#fff;text-align:center;border-radius:10px;padding:10px}\n"] }]
1501
+ args: [{ selector: 'croco-html-image-editor', standalone: true, imports: [MatButtonToggleGroup, FormsModule, MatButtonToggle, MatIcon, FileIdSelectComponent, MatFormField, MatLabel, MatInput, CdkDragHandle, MatCard, MatCardContent, XmlTagExternalVideoComponent, NgStyle, MatButton, MatIconButton, MatSlideToggle], template: "<div>\n <div style=\"height: 10px;\">\n </div>\n\n @if (hasImageError) {\n <div class=\"error-block\">\n \u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u043E \u043F\u043E \u0443\u043A\u0430\u0437\u0430\u043D\u043D\u043E\u043C\u0443 \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443, \u0432\u043E\u0437\u043C\u043E\u0436\u043D\u043E \u0444\u0430\u0439\u043B \u043D\u0435 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u0438\u043B\u0438 \u043E\u0442\u0441\u0443\u0442\u0441\u0442\u0432\u0443\u0435\u0442 \u043D\u0430 \u0441\u0435\u0440\u0432\u0435\u0440\u0435.\n </div>\n }\n\n @if (hasFileId() && !hasImageError) {\n <div>\n <img\n [ngStyle]=\"{ 'max-height': imageMaxHeight ? imageMaxHeight + 'px' : '100%'}\"\n class=\"mx-auto d-block img-fluid\" [src]=\"getSrc()\" (error)=\"onErrorHandler()\" alt=\"photo\"/>\n </div>\n }\n\n @if (!hasFileId()) {\n <div>\n <h5>[\u0418\u0437\u043E\u0431\u0440\u0430\u0436\u0435\u043D\u0438\u0435 \u043D\u0435 \u0432\u044B\u0431\u0440\u0430\u043D\u043E]</h5>\n </div>\n }\n\n @if(!tag.presentOrEdit) {\n <mat-slide-toggle style=\"padding: 10px 0\" [(ngModel)]=\"isShowMediaRequest\">\u041F\u043E\u043A\u0430\u0437\u044B\u0432\u0430\u0442\u044C \u043C\u0435\u0434\u0438\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B</mat-slide-toggle>\n }\n\n @if(isShowMediaRequest) {\n <div style=\"display: flex; flex-direction: column; gap: 20px\">\n <div class=\"media-request__header\">\n <span>\u041C\u0435\u0434\u0438\u0430 \u0437\u0430\u043F\u0440\u043E\u0441\u044B:</span>\n @if (!tag.presentOrEdit) {\n <button (click)=\"addNewMediaRequest()\" class=\"w-30\" mat-icon-button color=\"primary\">\n <mat-icon>add</mat-icon>\n </button>\n }\n </div>\n @for (request of requests; track $index) {\n <div class=\"media-request__container\">\n @if (tag.presentOrEdit) {\n <div style=\"display: flex; flex-direction: column; gap: 5px\">\n <span class=\"w-100\">\u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B: {{request.screenWidth}}</span>\n <span class=\"w-100\">\u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430: {{request.maxImageHeight}}</span>\n </div>\n }\n\n @if (!tag.presentOrEdit) {\n <div style=\"width: 100%\">\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B\n </mat-label>\n <input matInput placeholder=\"\u0413\u0440\u0430\u043D\u0438\u0446\u0430 \u0448\u0438\u0440\u0438\u043D\u044B\"\n autocomplete=\"off\"\n [(ngModel)]=\"request.screenWidth\"\n (ngModelChange)=\"requestChanged()\">\n </mat-form-field>\n\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430\n </mat-label>\n <input matInput placeholder=\" \u041C\u0430\u043A\u0441\u0438\u043C\u0430\u043B\u044C\u043D\u0430\u044F \u0432\u044B\u0441\u043E\u0442\u0430\"\n autocomplete=\"off\"\n [(ngModel)]=\"request.maxImageHeight\"\n (ngModelChange)=\"requestChanged()\">\n </mat-form-field>\n </div>\n\n <button (click)=\"deleteMediaRequest($index)\" class=\"w-30\" mat-icon-button color=\"warn\">\n <mat-icon>delete</mat-icon>\n </button>\n }\n </div>\n }\n </div>\n }\n</div>\n\n@if (!tag.presentOrEdit) {\n <div>\n <div style=\"height: 10px;\"></div>\n <div style=\"overflow-x:auto;\">\n <mat-button-toggle-group [(ngModel)]=\"searchOrEdit\">\n <mat-button-toggle value=\"search\">\n \u0418\u0441\u043A\u0430\u0442\u044C \u0444\u0430\u0439\u043B <mat-icon>search</mat-icon>\n </mat-button-toggle>\n <mat-button-toggle value=\"edit\">\n \u0423\u043A\u0430\u0437\u0430\u0442\u044C \u043F\u043E \u0438\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440\u0443 <mat-icon>settings</mat-icon>\n </mat-button-toggle>\n </mat-button-toggle-group>\n </div>\n <div style=\"height: 10px;\"></div>\n <div [hidden]=\"searchOrEdit !== 'search'\">\n <croco-html-file-id-select\n [labelText]=\"'\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B'\"\n [(fileId)]=\"tag.attributes['file-id']\"\n (onFileIdChanged)=\"onFileIdChanged($event)\">\n </croco-html-file-id-select>\n </div>\n <div [hidden]=\"searchOrEdit !== 'edit'\">\n <div>\n <mat-form-field class=\"w-100\">\n <mat-label>\n \u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\n </mat-label>\n <input matInput placeholder=\"\u0418\u0434\u0435\u043D\u0442\u0438\u0444\u0438\u043A\u0430\u0442\u043E\u0440 \u0444\u0430\u0439\u043B\u0430\" new-autocomplete=\"off\" autocomplete=\"off\"\n type=\"number\"\n [(ngModel)]=\"tag.attributes['file-id']\"\n (ngModelChange)=\"removeImageError()\">\n </mat-form-field>\n </div>\n </div>\n </div>\n}\n", styles: [".error-block{background-color:#f32323;color:#fff;text-align:center;border-radius:10px;padding:10px}.media-request__header{align-items:center;display:flex;width:100%;justify-content:space-between}.media-request__container{display:flex;align-items:center;border-bottom:1px solid rgba(128,128,128,.7);padding-bottom:10px}\n"] }]
1408
1502
  }], ctorParameters: () => [{ type: undefined, decorators: [{
1409
1503
  type: Inject,
1410
1504
  args: [CrocoHtmlOptionsToken]
1411
- }] }], propDecorators: { tag: [{
1505
+ }] }, { type: ScreenWidthService }], propDecorators: { tag: [{
1412
1506
  type: Input
1413
1507
  }], onTagUpdated: [{
1414
1508
  type: Output
@@ -1592,6 +1686,9 @@ class VisualEditorComponent {
1592
1686
  attrs[ExternalVideoTagDataConsts.VideoTypeAttrName] = this.selectedVideoPlayer;
1593
1687
  attrs[ExternalVideoTagDataConsts.LinkAttrName] = this.selectedVideoPlayer === ExternalVideoSupportedTypes.VkVideo ? defaultLinkVk : defaultLinkYouTube;
1594
1688
  }
1689
+ else if (tagDescription.tag == FileImageTagDataConsts.TagName) {
1690
+ attrs[FileImageTagDataConsts.ScreenMediaRequest] = FileImageTagDataConsts.DefaultValueForFileImage;
1691
+ }
1595
1692
  else if (tagDescription.tag == DownloadButtonTagDataConsts.TagName) {
1596
1693
  attrs[DownloadButtonTagDataConsts.LinkAttrName] = defaultLinkForDownload;
1597
1694
  attrs[DownloadButtonTagDataConsts.TitleAttrName] = 'Скачать';