mirror of https://github.com/Squidex/squidex.git
21 changed files with 319 additions and 89 deletions
@ -1,84 +1,100 @@ |
|||
<form [formGroup]="annotateForm.form" (ngSubmit)="annotateAsset()"> |
|||
<sqx-modal-dialog (close)="emitComplete()"> |
|||
<sqx-modal-dialog (close)="emitComplete()" size="xl" fullHeight="true" [showHeader]="true" [showFooter]="false"> |
|||
<ng-container title> |
|||
Update Asset |
|||
</ng-container> |
|||
|
|||
<ng-container tabs> |
|||
<ul class="nav nav-tabs2"> |
|||
<li class="nav-item" *ngFor="let tab of selectableTabs"> |
|||
<a class="nav-link" [class.active]="tab === selectedTab" (click)="selectTab(tab)">{{tab}}</a> |
|||
</li> |
|||
</ul> |
|||
|
|||
<button type="submit" class="float-right btn btn-primary" [disabled]="!isEditable">Save</button> |
|||
</ng-container> |
|||
|
|||
<ng-container content> |
|||
<sqx-form-error [error]="annotateForm.error | async"></sqx-form-error> |
|||
|
|||
<div class="form-group"> |
|||
<label for="fileName">Name</label> |
|||
<ng-container [ngSwitch]="selectedTab"> |
|||
<ng-container *ngSwitchCase="'Image'"> |
|||
<div class="image"> |
|||
<sqx-image-editor [imageUrl]="asset.contentUrl"></sqx-image-editor> |
|||
</div> |
|||
</ng-container> |
|||
<ng-container *ngSwitchCase="'Metadata'"> |
|||
<div class="metadata"> |
|||
<sqx-form-error [error]="annotateForm.error | async"></sqx-form-error> |
|||
|
|||
<div class="form-group"> |
|||
<label for="fileName">Name</label> |
|||
|
|||
<sqx-control-errors for="fileName" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control" id="fileName" formControlName="fileName" /> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label for="slug">Slug</label> |
|||
|
|||
<sqx-control-errors for="slug" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control slug" id="slug" formControlName="slug" sqxTransformInput="Slugify" /> |
|||
|
|||
<button type="button" class="btn btn-text-secondary btn-sm slug-generate" (click)="generateSlug()"> |
|||
Generate |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label>Tags</label> |
|||
|
|||
<sqx-control-errors for="tags" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<sqx-tag-editor [suggestions]="allTags" [allowDuplicates]="false" [undefinedWhenEmpty]="false" formControlName="tags"></sqx-tag-editor> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label>Metadata</label> |
|||
|
|||
<div class="form-group row no-gutters" *ngFor="let form of annotateForm.metadata.controls; let i = index"> |
|||
<div class="col col-name pr-1"> |
|||
<sqx-control-errors [for]="form.get('name')" fieldName="Name" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<sqx-control-errors for="fileName" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control" id="fileName" formControlName="fileName" /> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label for="slug">Slug</label> |
|||
<input type="text" class="form-control" maxlength="1000" [formControl]="form.get('name')" placeholder="Name" /> |
|||
</div> |
|||
|
|||
<sqx-control-errors for="slug" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control slug" id="slug" formControlName="slug" sqxTransformInput="Slugify" /> |
|||
|
|||
<button type="button" class="btn btn-text-secondary btn-sm btn-generate" (click)="generateSlug()"> |
|||
Generate |
|||
</button> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label>Tags</label> |
|||
<div class="col pr-1"> |
|||
<sqx-control-errors [for]="form.get('value')" fieldName="Value" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<sqx-control-errors for="tags" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<sqx-tag-editor [suggestions]="allTags" [allowDuplicates]="false" [undefinedWhenEmpty]="false" formControlName="tags"></sqx-tag-editor> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<label>Metadata</label> |
|||
|
|||
<div class="form-group row no-gutters" *ngFor="let form of annotateForm.metadata.controls; let i = index"> |
|||
<div class="col col-name pr-1"> |
|||
<sqx-control-errors [for]="form.get('name')" fieldName="Name" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control" maxlength="1000" [formControl]="form.get('name')" placeholder="Name" /> |
|||
<input type="text" class="form-control" maxlength="1000" [formControl]="form.get('value')" placeholder="Value" /> |
|||
</div> |
|||
|
|||
<div class="col-auto col-options"> |
|||
<button type="button" class="btn btn-text-danger" |
|||
[disabled]="!isEditable" |
|||
(sqxConfirmClick)="annotateForm.removeMetadata(i)" |
|||
confirmTitle="Remove url" |
|||
confirmText="Do you really want to remove this metadata?"> |
|||
<i class="icon-bin2"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<button type="button" class="btn btn-success" (click)="annotateForm.addMetadata()" [disabled]="!isEditable"> |
|||
Add Metadata |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group form-check"> |
|||
<input type="checkbox" class="form-check-input" id="isProtected" formControlName="isProtected" /> |
|||
|
|||
<label class="form-check-label" for="isProtected">Protected</label> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="col pr-1"> |
|||
<sqx-control-errors [for]="form.get('value')" fieldName="Value" [submitted]="annotateForm.submitted | async"></sqx-control-errors> |
|||
|
|||
<input type="text" class="form-control" maxlength="1000" [formControl]="form.get('value')" placeholder="Value" /> |
|||
</div> |
|||
|
|||
<div class="col-auto col-options"> |
|||
<button type="button" class="btn btn-text-danger" |
|||
[disabled]="!isEditable" |
|||
(sqxConfirmClick)="annotateForm.removeMetadata(i)" |
|||
confirmTitle="Remove url" |
|||
confirmText="Do you really want to remove this metadata?"> |
|||
<i class="icon-bin2"></i> |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group"> |
|||
<button type="button" class="btn btn-success" (click)="annotateForm.addMetadata()" [disabled]="!isEditable"> |
|||
Add Metadata |
|||
</button> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group form-check"> |
|||
<input type="checkbox" class="form-check-input" id="isProtected" formControlName="isProtected" /> |
|||
|
|||
<label class="form-check-label" for="isProtected">Protected</label> |
|||
</div> |
|||
</ng-container> |
|||
|
|||
<ng-container footer> |
|||
<button type="reset" class="float-left btn btn-secondary" (click)="emitComplete()">Cancel</button> |
|||
<button type="submit" class="float-right btn btn-primary" *ngIf="isEditable">Save</button> |
|||
</ng-container> |
|||
</ng-container> |
|||
</ng-container> |
|||
</sqx-modal-dialog> |
|||
</form> |
|||
@ -0,0 +1 @@ |
|||
<div #editor></div> |
|||
@ -0,0 +1,29 @@ |
|||
:host { |
|||
height: 100%; |
|||
} |
|||
|
|||
:host /deep/ { |
|||
.tui-image-editor-header { |
|||
display: none; |
|||
} |
|||
|
|||
* { |
|||
box-sizing: content-box; |
|||
} |
|||
|
|||
.tie-btn-delete { |
|||
display: none !important; |
|||
} |
|||
|
|||
.tie-btn-delete-all { |
|||
display: none !important; |
|||
|
|||
& + li { |
|||
display: none !important; |
|||
} |
|||
} |
|||
|
|||
svg { |
|||
vertical-align: baseline; |
|||
} |
|||
} |
|||
@ -0,0 +1,159 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved. |
|||
*/ |
|||
|
|||
import { AfterViewInit, ChangeDetectionStrategy, Component, ElementRef, Input, OnChanges, ViewChild } from '@angular/core'; |
|||
|
|||
import { ResourceLoaderService } from '@app/shared/internal'; |
|||
|
|||
declare var tui: any; |
|||
|
|||
const blackTheme = { |
|||
'common.bi.image': 'https://uicdn.toast.com/toastui/img/tui-image-editor-bi.png', |
|||
'common.bisize.width': '251px', |
|||
'common.bisize.height': '21px', |
|||
'common.backgroundImage': 'none', |
|||
'common.backgroundColor': '#000', |
|||
'common.border': '0px', |
|||
|
|||
// header
|
|||
'header.backgroundImage': 'none', |
|||
'header.backgroundColor': 'transparent', |
|||
'header.border': '0px', |
|||
|
|||
// load button
|
|||
'loadButton.backgroundColor': '#fff', |
|||
'loadButton.border': '1px solid #ddd', |
|||
'loadButton.color': '#222', |
|||
'loadButton.fontFamily': '\'Noto Sans\', sans-serif', |
|||
'loadButton.fontSize': '12px', |
|||
|
|||
// download button
|
|||
'downloadButton.backgroundColor': '#fdba3b', |
|||
'downloadButton.border': '1px solid #fdba3b', |
|||
'downloadButton.color': '#fff', |
|||
'downloadButton.fontFamily': '\'Noto Sans\', sans-serif', |
|||
'downloadButton.fontSize': '12px', |
|||
|
|||
// main icons
|
|||
'menu.normalIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-d.svg', |
|||
'menu.normalIcon.name': 'icon-d', |
|||
'menu.activeIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-b.svg', |
|||
'menu.activeIcon.name': 'icon-b', |
|||
'menu.disabledIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-a.svg', |
|||
'menu.disabledIcon.name': 'icon-a', |
|||
'menu.hoverIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-c.svg', |
|||
'menu.hoverIcon.name': 'icon-c', |
|||
'menu.iconSize.width': '24px', |
|||
'menu.iconSize.height': '24px', |
|||
|
|||
// submenu primary color
|
|||
'submenu.backgroundColor': '#000', |
|||
'submenu.partition.color': '#3c3c3c', |
|||
|
|||
// submenu icons
|
|||
'submenu.normalIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-d.svg', |
|||
'submenu.normalIcon.name': 'icon-d', |
|||
'submenu.activeIcon.path': 'https://unpkg.com/tui-image-editor@3.7.3/dist/svg/icon-c.svg', |
|||
'submenu.activeIcon.name': 'icon-c', |
|||
'submenu.iconSize.width': '32px', |
|||
'submenu.iconSize.height': '32px', |
|||
|
|||
// submenu labels
|
|||
'submenu.normalLabel.color': '#8a8a8a', |
|||
'submenu.normalLabel.fontWeight': 'normal', |
|||
'submenu.activeLabel.color': '#fff', |
|||
'submenu.activeLabel.fontWeight': 'normal', |
|||
|
|||
// checkbox style
|
|||
'checkbox.border': '0px', |
|||
'checkbox.backgroundColor': '#fff', |
|||
|
|||
// range style
|
|||
'range.pointer.color': '#fff', |
|||
'range.bar.color': '#666', |
|||
'range.subbar.color': '#d1d1d1', |
|||
|
|||
'range.disabledPointer.color': '#414141', |
|||
'range.disabledBar.color': '#282828', |
|||
'range.disabledSubbar.color': '#414141', |
|||
|
|||
'range.value.color': '#fff', |
|||
'range.value.fontWeight': 'normal', |
|||
'range.value.fontSize': '11px', |
|||
'range.value.border': '1px solid #353535', |
|||
'range.value.backgroundColor': '#151515', |
|||
'range.title.color': '#fff', |
|||
'range.title.fontWeight': 'normal', |
|||
|
|||
// colorpicker style
|
|||
'colorpicker.button.border': '1px solid #1e1e1e', |
|||
'colorpicker.title.color': '#fff' |
|||
}; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-image-editor', |
|||
styleUrls: ['./image-editor.component.scss'], |
|||
templateUrl: './image-editor.component.html', |
|||
changeDetection: ChangeDetectionStrategy.OnPush |
|||
}) |
|||
export class ImageEditorComponent implements AfterViewInit, OnChanges { |
|||
private imageEditor: any; |
|||
|
|||
@Input() |
|||
public imageUrl: string; |
|||
|
|||
@ViewChild('editor', { static: false }) |
|||
public editor: ElementRef; |
|||
|
|||
constructor( |
|||
private readonly resourceLoader: ResourceLoaderService |
|||
) { |
|||
} |
|||
|
|||
public ngOnChanges() { |
|||
if (this.imageEditor && this.imageUrl) { |
|||
this.imageEditor.loadImageFromURL(this.imageUrl); |
|||
} |
|||
} |
|||
|
|||
public ngAfterViewInit() { |
|||
const styles = [ |
|||
'https://uicdn.toast.com/tui-color-picker/latest/tui-color-picker.css', |
|||
'https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.css' |
|||
]; |
|||
|
|||
const scripts = [ |
|||
'https://cdnjs.cloudflare.com/ajax/libs/jquery/1.8.3/jquery.min.js', |
|||
'https://cdnjs.cloudflare.com/ajax/libs/fabric.js/3.3.2/fabric.js', |
|||
'https://uicdn.toast.com/tui.code-snippet/latest/tui-code-snippet.min.js', |
|||
'https://uicdn.toast.com/tui-color-picker/latest/tui-color-picker.js', |
|||
'https://uicdn.toast.com/tui-image-editor/latest/tui-image-editor.js' |
|||
]; |
|||
|
|||
styles.forEach(style => this.resourceLoader.loadStyle(style)); |
|||
|
|||
const s = scripts.map(script => this.resourceLoader.loadScript(script)); |
|||
|
|||
Promise.all(s).then(() => { |
|||
this.imageEditor = new tui.ImageEditor(this.editor.nativeElement, { |
|||
includeUI: { |
|||
loadImage: { |
|||
path: this.imageUrl, name: 'image' |
|||
}, |
|||
menu: [ |
|||
'crop', |
|||
'flip', |
|||
'rotate', |
|||
'mask', |
|||
'filter' |
|||
], |
|||
theme: blackTheme |
|||
} |
|||
}); |
|||
}); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue