Browse Source

Dropdown component.

pull/387/head
Sebastian Stehle 7 years ago
parent
commit
667c848765
  1. 20
      src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.html
  2. 12
      src/Squidex/app/features/apps/pages/apps-page.component.html
  3. 6
      src/Squidex/app/features/content/pages/content/content-page.component.html
  4. 4
      src/Squidex/app/features/content/shared/assets-editor.component.html
  5. 35
      src/Squidex/app/features/content/shared/content-item.component.html
  6. 57
      src/Squidex/app/features/content/shared/due-time-selector.component.html
  7. 8
      src/Squidex/app/features/content/shared/preview-button.component.html
  8. 4
      src/Squidex/app/features/content/shared/references-editor.component.html
  9. 6
      src/Squidex/app/features/rules/pages/rules/rules-page.component.html
  10. 83
      src/Squidex/app/features/schemas/pages/schema/field.component.html
  11. 79
      src/Squidex/app/features/schemas/pages/schema/schema-page.component.html
  12. 22
      src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.html
  13. 6
      src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts
  14. 7
      src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.html
  15. 118
      src/Squidex/app/features/settings/pages/clients/client.component.html
  16. 22
      src/Squidex/app/framework/angular/forms/autocomplete.component.html
  17. 22
      src/Squidex/app/framework/angular/forms/color-picker.component.html
  18. 14
      src/Squidex/app/framework/angular/forms/dropdown.component.html
  19. 20
      src/Squidex/app/framework/angular/forms/tag-editor.component.html
  20. 12
      src/Squidex/app/framework/angular/forms/tag-editor.component.ts
  21. 37
      src/Squidex/app/framework/angular/modals/dialog-renderer.component.html
  22. 2
      src/Squidex/app/framework/angular/modals/modal-dialog.component.html
  23. 114
      src/Squidex/app/framework/angular/modals/modal-target.directive.ts
  24. 157
      src/Squidex/app/framework/angular/modals/modal-view.directive.ts
  25. 254
      src/Squidex/app/framework/angular/modals/modal.component.ts
  26. 11
      src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.html
  27. 3
      src/Squidex/app/framework/angular/modals/root-view.component.html
  28. 2
      src/Squidex/app/framework/angular/modals/root-view.component.scss
  29. 7
      src/Squidex/app/framework/angular/modals/root-view.component.ts
  30. 5
      src/Squidex/app/framework/declarations.ts
  31. 15
      src/Squidex/app/framework/module.ts
  32. 2
      src/Squidex/app/framework/services/dialog.service.spec.ts
  33. 13
      src/Squidex/app/shared/components/asset.component.html
  34. 11
      src/Squidex/app/shared/components/language-selector.component.html
  35. 4
      src/Squidex/app/shared/components/markdown-editor.component.html
  36. 4
      src/Squidex/app/shared/components/rich-editor.component.html
  37. 62
      src/Squidex/app/shared/components/search-form.component.html
  38. 53
      src/Squidex/app/shell/pages/internal/apps-menu.component.html
  39. 38
      src/Squidex/app/shell/pages/internal/profile-menu.component.html

20
src/Squidex/app/features/administration/pages/event-consumers/event-consumers-page.component.html

@ -59,12 +59,14 @@
</ng-container>
</sqx-panel>
<sqx-modal-dialog *sqxModalView="eventConsumerErrorDialog;onRoot:true" (close)="eventConsumerErrorDialog.hide()">
<ng-container title>
Error
</ng-container>
<ng-container content>
<textarea readonly class="form-control error-message">{{eventConsumerError}}</textarea>
</ng-container>
</sqx-modal-dialog>
<sqx-modal [model]="eventConsumerErrorDialog">
<sqx-modal-dialog (close)="eventConsumerErrorDialog.hide()">
<ng-container title>
Error
</ng-container>
<ng-container content>
<textarea readonly class="form-control error-message">{{eventConsumerError}}</textarea>
</ng-container>
</sqx-modal-dialog>
</sqx-modal>

12
src/Squidex/app/features/apps/pages/apps-page.component.html

@ -102,20 +102,20 @@
<div *ngIf="info" class="info">{{info}}</div>
<ng-container *sqxModalView="addAppDialog;onRoot:true">
<sqx-modal [model]="addAppDialog">
<sqx-app-form [template]="addAppTemplate"
(complete)="addAppDialog.hide()">
</sqx-app-form>
</ng-container>
</sqx-modal>
<ng-container *sqxModalView="onboardingDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="onboardingDialog">
<sqx-onboarding-dialog
(close)="onboardingDialog.hide()">
</sqx-onboarding-dialog>
</ng-container>
</sqx-modal>
<ng-container *sqxModalView="newsDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="newsDialog">
<sqx-news-dialog [features]="newsFeatures"
(close)="newsDialog.hide()">
</sqx-news-dialog>
</ng-container>
</sqx-modal>

6
src/Squidex/app/features/content/pages/content/content-page.component.html

@ -44,8 +44,8 @@
</sqx-content-status>
</button>
<ng-container *ngIf="content.isPending || !schema.isSingleton">
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="optionsButton" @fade>
<sqx-modal *ngIf="content.isPending || !schema.isSingleton" [model]="dropdown" [target]="optionsButton" closeAlways="true">
<div class="dropdown-menu" @fade>
<a class="dropdown-item" (click)="discardChanges()" *ngIf="content.canDraftDiscard">
Discard changes
</a>
@ -72,7 +72,7 @@
</a>
</ng-container>
</div>
</ng-container>
</sqx-modal>
</div>
<button type="button" class="btn btn-secondary ml-1" (click)="saveAsDraft()" *ngIf="content.canDraftPropose">

4
src/Squidex/app/features/content/shared/assets-editor.component.html

@ -59,8 +59,8 @@
</div>
</div>
<ng-container *sqxModalView="assetsDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="assetsDialog">
<sqx-assets-selector
(select)="selectAssets($event)">
</sqx-assets-selector>
</ng-container>
</sqx-modal>

35
src/Squidex/app/features/content/shared/content-item.component.html

@ -55,23 +55,26 @@
<button type="button" class="btn btn-text-secondary" (click)="dropdown.toggle()" [class.active]="dropdown.isOpen | async" #optionsButton>
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="optionsButton" @fade>
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="emitChangeStatus(info.status)">
Change to <i class="icon-circle icon-sm" [style.color]="info.color"></i> {{info.status}}
</a>
<a class="dropdown-item" (click)="emitClone(); dropdown.hide()" *ngIf="canClone">
Clone
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="emitDelete()"
confirmTitle="Delete content"
confirmText="Do you really want to delete the content?">
Delete
</a>
</div>
<sqx-modal [model]="dropdown" [target]="optionsButton" closeAlways="true">
<div class="dropdown-menu" @fade>
<a class="dropdown-item" *ngFor="let info of content.statusUpdates" (click)="emitChangeStatus(info.status)">
Change to <i class="icon-circle icon-sm" [style.color]="info.color"></i> {{info.status}}
</a>
<a class="dropdown-item" (click)="emitClone(); dropdown.hide()" *ngIf="canClone">
Clone
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
(sqxConfirmClick)="emitDelete()"
confirmTitle="Delete content"
confirmText="Do you really want to delete the content?">
Delete
</a>
</div>
</sqx-modal>
</div>
</td>
<td class="cell-actions" *ngIf="isReference" [sqxStopClick]="isDirty">

57
src/Squidex/app/features/content/shared/due-time-selector.component.html

@ -1,28 +1,31 @@
<sqx-modal-dialog *sqxModalView="dueTimeDialog;onRoot:true" (close)="cancelStatusChange()">
<ng-container title>
{{dueTimeAction}} content item(s)
</ng-container>
<sqx-modal [model]="dueTimeDialog">
<sqx-modal-dialog (close)="cancelStatusChange()">
<ng-container title>
{{dueTimeAction}} content item(s)
</ng-container>
<ng-container content>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Immediately" id="immediately" name="dueTimeMode">
<label class="form-check-label" for="immediately">
{{dueTimeAction}} content item(s) immediately.
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Scheduled" id="scheduled" name="dueTimeMode">
<label class="form-check-label" for="scheduled">
{{dueTimeAction}} content item(s) at a later point date and time.
</label>
</div>
<sqx-date-time-editor [disabled]="dueTimeMode === 'Immediately'" mode="DateTime" hideClear="true" [(ngModel)]="dueTime"></sqx-date-time-editor>
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancelStatusChange()">Cancel</button>
<button type="button" class="float-right btn btn-primary" [disabled]="dueTimeMode === 'Scheduled' && !dueTime" (click)="confirmStatusChange()" sqxFocusOnInit>Confirm</button>
</ng-container>
</sqx-modal-dialog>
<ng-container content>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Immediately" id="immediately" name="dueTimeMode">
<label class="form-check-label" for="immediately">
{{dueTimeAction}} content item(s) immediately.
</label>
</div>
<div class="form-check">
<input class="form-check-input" type="radio" [(ngModel)]="dueTimeMode" value="Scheduled" id="scheduled" name="dueTimeMode">
<label class="form-check-label" for="scheduled">
{{dueTimeAction}} content item(s) at a later point date and time.
</label>
</div>
<sqx-date-time-editor [disabled]="dueTimeMode === 'Immediately'" mode="DateTime" hideClear="true" [(ngModel)]="dueTime"></sqx-date-time-editor>
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancelStatusChange()">Cancel</button>
<button type="button" class="float-right btn btn-primary" [disabled]="dueTimeMode === 'Scheduled' && !dueTime" (click)="confirmStatusChange()" sqxFocusOnInit>Confirm</button>
</ng-container>
</sqx-modal-dialog>
</sqx-modal>

8
src/Squidex/app/features/content/shared/preview-button.component.html

@ -9,9 +9,11 @@
<div class="btn-group" *ngIf="snapshot.alternativeNames.length > 0">
<button type="button" class="btn btn-secondary dropdown-toggle" (click)="dropdown.toggle()"></button>
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="buttonGroup" @fade>
<a *ngFor="let name of snapshot.alternativeNames" class="dropdown-item" (click)="follow(name)">{{name}}</a>
</div>
<sqx-modal [model]="dropdown" [target]="buttonGroup" closeAlways="true">
<div class="dropdown-menu" @fade>
<a *ngFor="let name of snapshot.alternativeNames" class="dropdown-item" (click)="follow(name)">{{name}}</a>
</div>
</sqx-modal>
</div>
</div>
</ng-container>

4
src/Squidex/app/features/content/shared/references-editor.component.html

@ -27,7 +27,7 @@
</div>
</div>
<ng-container *sqxModalView="selectorDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="selectorDialog">
<sqx-contents-selector
[allowDuplicates]="allowDuplicates"
[alreadySelected]="snapshot.contentItems"
@ -36,4 +36,4 @@
[schema]="snapshot.schema"
(select)="select($event)">
</sqx-contents-selector>
</ng-container>
</sqx-modal>

6
src/Squidex/app/features/rules/pages/rules/rules-page.component.html

@ -67,8 +67,8 @@
</tbody>
</table>
<ng-container *sqxModalView="addRuleDialog;onRoot:true;closeAuto:false">
<sqx-rule-wizard
<sqx-modal [model]="addRuleDialog">
<sqx-rule-wizard
[schemas]="schemasState.schemas | async"
[rule]="wizardRule"
[ruleActions]="ruleActions"
@ -76,7 +76,7 @@
[mode]="wizardMode"
(complete)="addRuleDialog.hide()">
</sqx-rule-wizard>
</ng-container>
</sqx-modal>
</ng-container>
</ng-container>

83
src/Squidex/app/features/schemas/pages/schema/field.component.html

@ -28,45 +28,48 @@
<button type="button" class="btn btn-text-secondary ml-1" (click)="dropdown.toggle()" [disabled]="!field.properties.isContentField && field.isLocked" [class.active]="dropdown.isOpen | async" #optionsButton>
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="optionsButton" @fade>
<ng-container *ngIf="field.properties.isContentField">
<a class="dropdown-item" (click)="enableField()" *ngIf="field.canEnable">
Enable in UI
</a>
<a class="dropdown-item" (click)="disableField()" *ngIf="field.canDisable">
Disable in UI
</a>
<a class="dropdown-item" (click)="hideField()" *ngIf="field.canHide">
Hide in API
</a>
<a class="dropdown-item" (click)="showField()" *ngIf="field.canShow">
Show in API
</a>
</ng-container>
<ng-container *ngIf="field.canLock">
<div class="dropdown-divider"></div>
<a class="dropdown-item"
(sqxConfirmClick)="lockField()"
confirmTitle="Lock field"
confirmText="Do you really want to lock the field? Locked fields cannot be deleted or changed anymore.">
Lock and prevent changes
</a>
</ng-container>
<ng-container>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
[class.disabled]="!field.canDelete"
(sqxConfirmClick)="deleteField()"
confirmTitle="Delete field"
confirmText="Do you really want to delete the field?">
Delete
</a>
</ng-container>
</div>
<sqx-modal [model]="dropdown" [target]="optionsButton" closeAlways="true">
<div class="dropdown-menu" @fade>
<ng-container *ngIf="field.properties.isContentField">
<a class="dropdown-item" (click)="enableField()" *ngIf="field.canEnable">
Enable in UI
</a>
<a class="dropdown-item" (click)="disableField()" *ngIf="field.canDisable">
Disable in UI
</a>
<a class="dropdown-item" (click)="hideField()" *ngIf="field.canHide">
Hide in API
</a>
<a class="dropdown-item" (click)="showField()" *ngIf="field.canShow">
Show in API
</a>
</ng-container>
<ng-container *ngIf="field.canLock">
<div class="dropdown-divider"></div>
<a class="dropdown-item"
(sqxConfirmClick)="lockField()"
confirmTitle="Lock field"
confirmText="Do you really want to lock the field? Locked fields cannot be deleted or changed anymore.">
Lock and prevent changes
</a>
</ng-container>
<ng-container>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
[class.disabled]="!field.canDelete"
(sqxConfirmClick)="deleteField()"
confirmTitle="Delete field"
confirmText="Do you really want to delete the field?">
Delete
</a>
</ng-container>
</div>
</sqx-modal>
</div>
</div>
</div>
@ -110,11 +113,11 @@
</button>
</div>
<ng-container *sqxModalView="addFieldDialog;onRoot:true;closeAuto:false;closeAlways:true">
<sqx-modal [model]="addFieldDialog">
<sqx-field-wizard [schema]="schema" [parent]="field"
(complete)="addFieldDialog.hide()">
</sqx-field-wizard>
</ng-container>
</sqx-modal>
</ng-container>
</div>
</div>

79
src/Squidex/app/features/schemas/pages/schema/schema-page.component.html

@ -23,34 +23,37 @@
<button type="button" class="btn btn-text-secondary ml-1" (click)="editOptionsDropdown.toggle()" [class.active]="editOptionsDropdown.isOpen | async" #buttonOptions>
<i class="icon-dots"></i>
</button>
<div class="dropdown-menu" *sqxModalView="editOptionsDropdown;closeAlways:true" [sqxModalTarget]="buttonOptions" @fade>
<a class="dropdown-item" (click)="configureScriptsDialog.show()">
Scripts
</a>
<a class="dropdown-item" (click)="configurePreviewUrlsDialog.show()">
Preview Urls
</a>
<ng-container *ngIf="schemasState.canCreate">
<div class="dropdown-divider"></div>
<a class="dropdown-item" (click)="cloneSchema()">
Clone
<sqx-modal [model]="editOptionsDropdown" [target]="buttonOptions" closeAlways="true">
<div class="dropdown-menu" @fade>
<a class="dropdown-item" (click)="configureScriptsDialog.show()">
Scripts
</a>
</ng-container>
<ng-container>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
[class.disabled]="!schema.canDelete"
(sqxConfirmClick)="deleteSchema()"
confirmTitle="Delete schema"
confirmText="Do you really want to delete the schema?">
Delete
<a class="dropdown-item" (click)="configurePreviewUrlsDialog.show()">
Preview Urls
</a>
</ng-container>
</div>
<ng-container *ngIf="schemasState.canCreate">
<div class="dropdown-divider"></div>
<a class="dropdown-item" (click)="cloneSchema()">
Clone
</a>
</ng-container>
<ng-container>
<div class="dropdown-divider"></div>
<a class="dropdown-item dropdown-item-delete"
[class.disabled]="!schema.canDelete"
(sqxConfirmClick)="deleteSchema()"
confirmTitle="Delete schema"
confirmText="Do you really want to delete the schema?">
Delete
</a>
</ng-container>
</div>
</sqx-modal>
</div>
<sqx-onboarding-tooltip helpId="history" [for]="buttonOptions" position="bottom-right" after="60000">
@ -98,31 +101,31 @@
<router-outlet></router-outlet>
<ng-container *sqxModalView="editSchemaDialog;onRoot:true">
<sqx-modal [model]="editSchemaDialog">
<sqx-schema-edit-form [schema]="schema"
(complete)="editSchemaDialog.hide()">
</sqx-schema-edit-form>
</ng-container>
</sqx-modal>
<ng-container *sqxModalView="addFieldDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="addFieldDialog">
<sqx-field-wizard [schema]="schema"
(complete)="addFieldDialog.hide()">
</sqx-field-wizard>
</ng-container>
</sqx-modal>
<ng-container *sqxModalView="configureScriptsDialog;onRoot:true">
<sqx-modal [model]="configureScriptsDialog">
<sqx-schema-scripts-form [schema]="schema"
(complete)="configureScriptsDialog.hide()">
</sqx-schema-scripts-form>
</ng-container>
</sqx-schema-scripts-form>
</sqx-modal>
<ng-container *sqxModalView="configurePreviewUrlsDialog;onRoot:true">
<sqx-modal [model]="configurePreviewUrlsDialog">
<sqx-schema-preview-urls-form [schema]="schema"
(complete)="configurePreviewUrlsDialog.hide()">
</sqx-schema-preview-urls-form>
</ng-container>
</sqx-modal>
<ng-container *sqxModalView="exportSchemaDialog;onRoot:true">
<sqx-modal [model]="exportSchemaDialog">
<sqx-modal-dialog (close)="exportSchemaDialog.hide()" large="true">
<ng-container title>
Export Schema
@ -133,5 +136,5 @@
<sqx-json-editor disabled [ngModel]="schemaExport"></sqx-json-editor>
</div>
</ng-container>
</sqx-modal-dialog>
</ng-container>
</sqx-modal-dialog>
</sqx-modal>

22
src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.html

@ -38,20 +38,24 @@
<label class="col-3 col-form-label" for="{{field.fieldId}}_fieldPattern">Pattern</label>
<div class="col-6">
<input type="text" class="form-control" id="{{field.fieldId}}_fieldPattern" formControlName="pattern" placeholder="Regex Pattern" #patternInput
<input type="text" class="form-control" id="{{field.fieldId}}_fieldPattern" formControlName="pattern" placeholder="Regex Pattern" #inputPattern
autocomplete="off"
autocorrect="off"
autocapitalize="off"
(focus)="patternsModal.show()" (blur)="patternsModal.hide()" />
<div *ngIf="patterns.length > 0 && (patternsModal.isOpen | async) && (showPatternSuggestions | async)" [sqxModalTarget]="patternInput" class="control-dropdown">
<h4>Suggestions</h4>
<div *ngFor="let pattern of patterns" class="control-dropdown-item control-dropdown-item-selectable" (mousedown)="setPattern(pattern)">
<div class="truncate">{{pattern.name}}</div>
<div class="truncate text-muted">{{pattern.pattern}}</div>
</div>
</div>
<ng-container *ngIf="patterns.length > 0 && (showPatternSuggestions | async)">
<sqx-modal [model]="patternsModal" [target]="inputPattern" position="bottom-left">
<div class="control-dropdown" @fade>
<h4>Suggestions</h4>
<div *ngFor="let pattern of patterns" class="control-dropdown-item control-dropdown-item-selectable" (mousedown)="setPattern(pattern)">
<div class="truncate">{{pattern.name}}</div>
<div class="truncate text-muted">{{pattern.pattern}}</div>
</div>
</div>
</sqx-modal>
</ng-container>
</div>
<small class="col-3" style="align-self: center">
{{patternName}}

6
src/Squidex/app/features/schemas/pages/schema/types/string-validation.component.ts

@ -10,6 +10,7 @@ import { FormControl, FormGroup } from '@angular/forms';
import { Observable } from 'rxjs';
import {
fadeAnimation,
FieldDto,
hasNoValue$,
ImmutableArray,
@ -24,7 +25,10 @@ import {
@Component({
selector: 'sqx-string-validation',
styleUrls: ['string-validation.component.scss'],
templateUrl: 'string-validation.component.html'
templateUrl: 'string-validation.component.html',
animations: [
fadeAnimation
]
})
export class StringValidationComponent extends ResourceOwner implements OnInit {
@Input()

7
src/Squidex/app/features/schemas/pages/schemas/schemas-page.component.html

@ -38,11 +38,10 @@
</ng-container>
</sqx-panel>
<ng-container *sqxModalView="addSchemaDialog;onRoot:true">
<sqx-modal [model]="addSchemaDialog">
<sqx-schema-form [import]="import"
(cancel)="addSchemaDialog.hide()"
(complete)="redirectSchema($event)">
(cancel)="addSchemaDialog.hide()" (complete)="redirectSchema($event)">
</sqx-schema-form>
</ng-container>
</sqx-modal>
<router-outlet></router-outlet>

118
src/Squidex/app/features/settings/pages/clients/client.component.html

@ -70,70 +70,72 @@
</div>
</div>
<sqx-modal-dialog *sqxModalView="connectDialog;onRoot:true" large="true" (close)="connectDialog.hide()">
<ng-container title>
Connect
</ng-container>
<sqx-modal [model]="connectDialog">
<sqx-modal-dialog large="true" (close)="connectDialog.hide()">
<ng-container title>
Connect
</ng-container>
<ng-container content>
<div class="help">
<h2>How to connect to this client</h2>
<h3>Using HTTP</h3>
<p>
1. Make the following request to get an access token. It will be valid for 30 days.
<ng-container content>
<div class="help">
<h2>How to connect to this client</h2>
<sqx-code>{{connectHttpText}}</sqx-code>
</p>
<p>
2. Add the bearer token as authorization header to all requests:
<sqx-code>Authorization: Bearer [YOUR_TOKEN]</sqx-code>
</p>
<h3>Using HTTP</h3>
<p>
1. Make the following request to get an access token. It will be valid for 30 days.
<sqx-code>{{connectHttpText}}</sqx-code>
</p>
<p>
2. Add the bearer token as authorization header to all requests:
<sqx-code>Authorization: Bearer [YOUR_TOKEN]</sqx-code>
</p>
<p>
Use the following token for testing
<p>
Use the following token for testing
<sqx-code>{{connectToken?.accessToken}}</sqx-code>
</p>
<h3>Using the command line interface (CLI)</h3>
<p>
Download the CLI here: <a href="https://github.com/Squidex/squidex-samples/releases" sqxExternalLink>CLI Releases (Linux, OS X, Windows)</a>
</p>
<p>
Connect with .NET SDK:
<sqx-code>{{connectToken?.accessToken}}</sqx-code>
</p>
<h3>Using the command line interface (CLI)</h3>
<p>
Download the CLI here: <a href="https://github.com/Squidex/squidex-samples/releases" sqxExternalLink>CLI Releases (Linux, OS X, Windows)</a>
</p>
<p>
Connect with .NET SDK:
<sqx-code>{{connectCLINetText}}</sqx-code>
</p>
<p>
Connect with Windows:
<sqx-code>{{connectCLINetText}}</sqx-code>
</p>
<p>
Connect with Windows:
<sqx-code>{{connectCLIWinText}}</sqx-code>
</p>
<p>
Connect with Linux / OS X
<sqx-code>{{connectCLIWinText}}</sqx-code>
</p>
<p>
Connect with Linux / OS X
<sqx-code>{{connectCLINixText}}</sqx-code>
</p>
<h3>Using the C# Client Library</h3>
<sqx-code>{{connectCLINixText}}</sqx-code>
</p>
<h3>Using the C# Client Library</h3>
<p>
Get the nuget library from <a href="https://www.nuget.org/packages/Squidex.ClientLibrary/" sqxExternalLink>nuget.org</a>
</p>
<p>
Create a client manager
<p>
Get the nuget library from <a href="https://www.nuget.org/packages/Squidex.ClientLibrary/" sqxExternalLink>nuget.org</a>
</p>
<p>
Create a client manager
<sqx-code>{{connectLibraryText}}</sqx-code>
</p>
</div>
</ng-container>
</sqx-modal-dialog>
<sqx-code>{{connectLibraryText}}</sqx-code>
</p>
</div>
</ng-container>
</sqx-modal-dialog>
</sqx-modal>

22
src/Squidex/app/framework/angular/forms/autocomplete.component.html

@ -5,17 +5,19 @@
autocorrect="off"
autocapitalize="off">
<div *ngIf="snapshot.suggestedItems.length > 0" [sqxModalTarget]="input" class="control-dropdown" #container position="bottom-left">
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
[container]="container"
(mousedown)="selectItem(item)"
(mouseover)="selectIndex(i)"
[sqxScrollActive]="i === snapshot.suggestedIndex">
<sqx-modal [model]="snapshot.suggestedItems.length > 0" [target]="input" position="bottom-left">
<div class="control-dropdown" #container>
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
[container]="container"
(mousedown)="selectItem(item)"
(mouseover)="selectIndex(i)"
[sqxScrollActive]="i === snapshot.suggestedIndex">
<ng-container *ngIf="!itemTemplate">{{item}}</ng-container>
<ng-container *ngIf="!itemTemplate">{{item}}</ng-container>
<ng-template *ngIf="itemTemplate" [sqxTemplateWrapper]="itemTemplate" [item]="item" [index]="i"></ng-template>
<ng-template *ngIf="itemTemplate" [sqxTemplateWrapper]="itemTemplate" [item]="item" [index]="i"></ng-template>
</div>
</div>
</div>
</sqx-modal>
</span>

22
src/Squidex/app/framework/angular/forms/color-picker.component.html

@ -14,14 +14,16 @@
</ng-template>
</span>
<div *sqxModalView="modal" [sqxModalTarget]="input" position="bottom-left"
[style.height]="'228px'"
[style.width]="'130px'">
<div [style.background]="snapshot.value"
[cpToggle]="true"
[cpDialogDisplay]="'inline'"
[cpCancelButton]="false"
[colorPicker]="snapshot.value"
(colorPickerChange)="updateValue($event)">
<sqx-modal [model]="modal" [target]="input" closeAlways="true" position="bottom-left">
<div
[style.height]="'228px'"
[style.width]="'130px'">
<div [style.background]="snapshot.value"
[cpToggle]="true"
[cpDialogDisplay]="'inline'"
[cpCancelButton]="false"
[colorPicker]="snapshot.value"
(colorPickerChange)="updateValue($event)">
</div>
</div>
</div>
</sqx-modal>

14
src/Squidex/app/framework/angular/forms/dropdown.component.html

@ -15,12 +15,14 @@
</div>
<div class="items-container">
<div class="control-dropdown" #container *sqxModalView="dropdown" [sqxModalTarget]="input" position="bottom-left">
<div *ngFor="let item of items; let i = index;" class="control-dropdown-item control-dropdown-item-selectable" [class.active]="i === snapshot.selectedIndex" (mousedown)="selectIndexAndClose(i)" [sqxScrollActive]="i === snapshot.selectedIndex" [container]="container">
<ng-container *ngIf="!templateItem">{{item}}</ng-container>
<ng-template *ngIf="templateItem" [sqxTemplateWrapper]="templateItem" [item]="item" [index]="i"></ng-template>
<sqx-modal [model]="dropdown" [target]="input" position="bottom-left">
<div class="control-dropdown" #container>
<div *ngFor="let item of items; let i = index;" class="control-dropdown-item control-dropdown-item-selectable" [class.active]="i === snapshot.selectedIndex" (mousedown)="selectIndexAndClose(i)" [sqxScrollActive]="i === snapshot.selectedIndex" [container]="container">
<ng-container *ngIf="!templateItem">{{item}}</ng-container>
<ng-template *ngIf="templateItem" [sqxTemplateWrapper]="templateItem" [item]="item" [index]="i"></ng-template>
</div>
</div>
</div>
</sqx-modal>
</div>
</span>

20
src/Squidex/app/framework/angular/forms/tag-editor.component.html

@ -22,13 +22,15 @@
spellcheck="false">
</div>
<div *ngIf="snapshot.suggestedItems.length > 0" [sqxModalTarget]="form" class="control-dropdown" #container position="bottom-left">
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
[container]="container"
(mousedown)="selectValue(item)"
(mouseover)="selectIndex(i)"
[sqxScrollActive]="i === snapshot.suggestedIndex">
<ng-container>{{item}}</ng-container>
<sqx-modal [model]="snapshot.suggestedItems.length > 0" [target]="form">
<div class="control-dropdown" #container @fade>
<div *ngFor="let item of snapshot.suggestedItems; let i = index" class="control-dropdown-item control-dropdown-item-selectable"
[class.active]="i === snapshot.suggestedIndex"
[container]="container"
(mousedown)="selectValue(item)"
(mouseover)="selectIndex(i)"
[sqxScrollActive]="i === snapshot.suggestedIndex">
<ng-container>{{item}}</ng-container>
</div>
</div>
</div>
</sqx-modal>

12
src/Squidex/app/framework/angular/forms/tag-editor.component.ts

@ -11,7 +11,12 @@ import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, E
import { FormControl, NG_VALUE_ACCESSOR } from '@angular/forms';
import { distinctUntilChanged, map, tap } from 'rxjs/operators';
import { Keys, StatefulControlComponent, Types } from '@app/framework/internal';
import {
fadeAnimation,
Keys,
StatefulControlComponent,
Types
} from '@app/framework/internal';
export const CONVERSION_FAILED = {};
@ -135,7 +140,10 @@ interface State {
styleUrls: ['./tag-editor.component.scss'],
templateUrl: './tag-editor.component.html',
providers: [SQX_TAG_EDITOR_CONTROL_VALUE_ACCESSOR],
changeDetection: ChangeDetectionStrategy.OnPush
changeDetection: ChangeDetectionStrategy.OnPush,
animations: [
fadeAnimation
]
})
export class TagEditorComponent extends StatefulControlComponent<State, any[]> implements AfterViewInit, OnInit {
@ViewChild('form', { static: false })

37
src/Squidex/app/framework/angular/modals/dialog-renderer.component.html

@ -1,19 +1,22 @@
<ng-content></ng-content>
<sqx-modal-dialog *sqxModalView="dialogView;onRoot:true" showClose="false" (close)="cancel()">
<ng-container title>
{{snapshot.dialogRequest?.title}}
</ng-container>
<ng-container content>
{{snapshot.dialogRequest?.text}}
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancel()">No</button>
<button type="button" class="float-right btn btn-danger" (click)="confirm()" sqxFocusOnInit>Yes</button>
</ng-container>
</sqx-modal-dialog>
<sqx-modal [model]="dialogView">
<sqx-modal-dialog showClose="false" (close)="cancel()">
<ng-container title>
{{snapshot.dialogRequest?.title}}
</ng-container>
<ng-container content>
{{snapshot.dialogRequest?.text}}
</ng-container>
<ng-container footer>
<button type="button" class="float-left btn btn-secondary" (click)="cancel()">No</button>
<button type="button" class="float-right btn btn-danger" (click)="confirm()" sqxFocusOnInit>Yes</button>
</ng-container>
</sqx-modal-dialog>
</sqx-modal>
<div class="notification-container notification-container-bottom-right">
<div class="alert alert-dismissible alert-{{notification.messageType}}" *ngFor="let notification of snapshot.notifications" (click)="close(notification)" @fade>
@ -24,7 +27,9 @@
</div>
<ng-container *ngIf="snapshot.tooltip; let tooltip">
<div class="tooltip2 tooltip2-{{tooltip.position}}" [sqxModalTarget]="tooltip.target" [position]="tooltip.position" [offset]="8">
{{tooltip.text}}
</div>
<sqx-modal [model]="true" [target]="tooltip.target" [position]="tooltip.position" [offset]="6">
<div class="tooltip2 tooltip2-{{tooltip.position}}">
{{tooltip.text}}
</div>
</sqx-modal>
</ng-container>

2
src/Squidex/app/framework/angular/modals/modal-dialog.component.html

@ -1,6 +1,4 @@
<div class="modal" @fade>
<div class="modal-backdrop show"></div>
<div class="modal-dialog" [class.modal-lg]="large" [class.modal-fh]="fullHeight">
<div class="modal-content">
<div class="modal-header" *ngIf="showHeader">

114
src/Squidex/app/framework/angular/modals/modal-target.directive.ts

@ -1,114 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, Directive, ElementRef, Input, OnDestroy, Renderer2 } from '@angular/core';
import { timer } from 'rxjs';
import { positionModal, ResourceOwner } from '@app/framework/internal';
@Directive({
selector: '[sqxModalTarget]'
})
export class ModalTargetDirective extends ResourceOwner implements AfterViewInit, OnDestroy {
private targetElement: Element;
@Input('sqxModalTarget')
public set target(element: Element) {
if (element !== this.targetElement) {
this.unsubscribeAll();
this.targetElement = element;
if (element) {
this.subscribe(element);
this.updatePosition();
}
}
}
@Input()
public offset = 2;
@Input()
public position = 'bottom-right';
@Input()
public autoPosition = true;
constructor(
private readonly renderer: Renderer2,
private readonly element: ElementRef<Element>
) {
super();
}
private subscribe(element: any) {
this.own(
this.renderer.listen(element, 'resize', () => {
this.updatePosition();
}));
this.own(
this.renderer.listen(this.element.nativeElement, 'resize', () => {
this.updatePosition();
}));
this.own(timer(100, 100).subscribe(() => this.updatePosition()));
}
public ngAfterViewInit() {
const modalRef = this.element.nativeElement;
this.renderer.setStyle(modalRef, 'position', 'fixed');
this.renderer.setStyle(modalRef, 'z-index', '1000000');
this.updatePosition();
}
private updatePosition() {
if (!this.targetElement) {
return;
}
const modalRef = this.element.nativeElement;
const modalRect = this.element.nativeElement.getBoundingClientRect();
if (modalRect.width === 0 || modalRect.height === 0) {
return;
}
const targetRect = this.targetElement.getBoundingClientRect();
let y = 0;
let x = 0;
if (this.position === 'full') {
x = -this.offset + targetRect.left;
y = -this.offset + targetRect.top;
const w = 2 * this.offset + targetRect.width;
const h = 2 * this.offset + targetRect.height;
this.renderer.setStyle(modalRef, 'width', `${w}px`);
this.renderer.setStyle(modalRef, 'height', `${h}px`);
} else {
const viewH = document.documentElement!.clientHeight;
const viewW = document.documentElement!.clientWidth;
const position = positionModal(targetRect, modalRect, this.position, this.offset, this.autoPosition, viewW, viewH);
x = position.x;
y = position.y;
}
this.renderer.setStyle(modalRef, 'top', `${y}px`);
this.renderer.setStyle(modalRef, 'left', `${x}px`);
this.renderer.setStyle(modalRef, 'right', 'auto');
this.renderer.setStyle(modalRef, 'bottom', 'auto');
this.renderer.setStyle(modalRef, 'margin', '0');
}
}

157
src/Squidex/app/framework/angular/modals/modal-view.directive.ts

@ -1,157 +0,0 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { ChangeDetectorRef, Directive, EmbeddedViewRef, Input, OnChanges, OnDestroy, Renderer2, SimpleChanges, TemplateRef, ViewContainerRef } from '@angular/core';
import { Subscription } from 'rxjs';
import {
DialogModel,
ModalModel,
Types
} from '@app/framework/internal';
import { RootViewComponent } from './root-view.component';
@Directive({
selector: '[sqxModalView]'
})
export class ModalViewDirective implements OnChanges, OnDestroy {
private modalSubscription: Subscription | null = null;
private renderedView: EmbeddedViewRef<any> | null = null;
@Input('sqxModalView')
public modalView: DialogModel | ModalModel | any;
@Input('sqxModalViewOnRoot')
public placeOnRoot = false;
@Input('sqxModalViewCloseAuto')
public closeAuto = true;
@Input('sqxModalViewCloseAlways')
public closeAlways = false;
constructor(
private readonly changeDetector: ChangeDetectorRef,
private readonly renderer: Renderer2,
private readonly rootView: RootViewComponent,
private readonly templateRef: TemplateRef<any>,
private readonly viewContainer: ViewContainerRef
) {
}
public ngOnDestroy() {
this.unsubscribeToModal();
this.unsubscribeToClick();
if (Types.is(this.modalView, DialogModel) || Types.is(this.modalView, ModalModel)) {
this.modalView.hide();
}
}
public ngOnChanges(changes: SimpleChanges) {
if (!changes['modalView']) {
return;
}
this.unsubscribeToModal();
if (Types.is(this.modalView, DialogModel) || Types.is(this.modalView, ModalModel)) {
this.modalSubscription =
this.modalView.isOpen.subscribe(isOpen => {
this.update(isOpen);
});
} else {
this.update(!!this.modalView);
}
}
private update(isOpen: boolean) {
if (isOpen === (!!this.renderedView)) {
return;
}
this.unsubscribeToClick();
if (isOpen && !this.renderedView) {
const container = this.getContainer();
this.renderedView = container.createEmbeddedView(this.templateRef);
if (this.renderedView.rootNodes[0].style) {
this.renderer.setStyle(this.renderedView.rootNodes[0], 'display', 'block');
}
this.startListening();
this.changeDetector.detectChanges();
} else if (!isOpen && this.renderedView) {
const container = this.getContainer();
const containerIndex = container.indexOf(this.renderedView);
container.remove(containerIndex);
this.renderedView = null;
this.changeDetector.detectChanges();
}
}
private getContainer() {
return this.placeOnRoot ? this.rootView.viewContainer : this.viewContainer;
}
private startListening() {
if (this.closeAuto) {
document.addEventListener('click', this.documentClickListener, true);
}
}
private documentClickListener = (event: MouseEvent) => {
if (!event.target || this.renderedView === null) {
return;
}
if (this.renderedView.rootNodes.length === 0) {
return;
}
if (this.closeAlways) {
const modal = this.modalView;
setTimeout(() => {
modal.hide();
}, 100);
} else {
try {
const rootNode = this.renderedView.rootNodes[0];
const rootBounds = rootNode.getBoundingClientRect();
if (rootBounds.width > 0 && rootBounds.height > 0) {
const clickedInside = rootNode.contains(event.target);
if (!clickedInside && this.modalView) {
this.modalView.hide();
}
}
} catch (ex) {
return;
}
}
}
private unsubscribeToModal() {
if (this.modalSubscription) {
this.modalSubscription.unsubscribe();
this.modalSubscription = null;
}
}
private unsubscribeToClick() {
document.removeEventListener('click', this.documentClickListener);
}
}

254
src/Squidex/app/framework/angular/modals/modal.component.ts

@ -0,0 +1,254 @@
/*
* Squidex Headless CMS
*
* @license
* Copyright (c) Squidex UG (haftungsbeschränkt). All rights reserved.
*/
import { AfterViewInit, ChangeDetectorRef, Component, EmbeddedViewRef, Input, OnDestroy, Renderer2, TemplateRef, ViewChild } from '@angular/core';
import { timer } from 'rxjs';
import {
DialogModel,
ModalModel,
positionModal,
ResourceOwner,
Types
} from '@app/framework/internal';
import { RootViewComponent } from './root-view.component';
declare type Model = DialogModel | ModalModel | any;
@Component({
selector: 'sqx-modal',
template: `
<ng-template #templatePortalContent>
<ng-content></ng-content>
</ng-template>
`
})
export class ModalComponent implements AfterViewInit, OnDestroy {
private readonly eventsView = new ResourceOwner();
private readonly eventsModel = new ResourceOwner();
private currentTarget: Element | null = null;
private currentModel: DialogModel | ModalModel | null = null;
private renderedView: EmbeddedViewRef<any> | null = null;
private renderRoot: HTMLElement | null = null;
private isOpen: boolean;
@Input()
public target: Element;
@Input()
public set model(value: Model) {
if (this.currentModel !== value) {
this.currentModel = value;
this.eventsModel.unsubscribeAll();
this.subscribeToModel(value);
}
}
@Input()
public offset = 2;
@Input()
public position = 'bottom-right';
@Input()
public autoPosition = true;
@Input()
public backdrop = true;
@Input()
public closeAuto = true;
@Input()
public closeAlways = false;
@ViewChild('templatePortalContent', { static: false })
public templateRef: TemplateRef<any>;
constructor(
private readonly changeDetector: ChangeDetectorRef,
private readonly renderer: Renderer2,
private readonly rootView: RootViewComponent
) {
}
public ngAfterViewInit() {
this.update(this.isOpen);
}
public ngOnDestroy() {
hideModal(this.currentModel);
this.eventsView.unsubscribeAll();
this.eventsModel.unsubscribeAll();
}
public onClick() {
if (this.closeAlways) {
this.model.hide();
}
}
private update(isOpen: boolean) {
if (!this.templateRef || this.isOpen === isOpen) {
return;
}
this.eventsView.unsubscribeAll();
if (isOpen) {
if (!this.renderedView) {
this.currentTarget = this.target;
this.renderedView = this.rootView.viewContainer.createEmbeddedView(this.templateRef);
this.renderRoot = this.renderedView.rootNodes[0];
this.setupStyles();
this.subscribeToView();
this.changeDetector.detectChanges();
}
} else {
if (this.renderedView) {
this.renderedView.destroy();
this.renderedView = null;
this.renderRoot = null;
this.changeDetector.detectChanges();
}
}
this.isOpen = isOpen;
}
private setupStyles() {
this.renderer.setStyle(this.renderRoot, 'display', 'block');
this.renderer.setStyle(this.renderRoot, 'right', 'auto');
this.renderer.setStyle(this.renderRoot, 'bottom', 'auto');
this.renderer.setStyle(this.renderRoot, 'margin', '0');
this.renderer.setStyle(this.renderRoot, 'position', 'fixed');
this.renderer.setStyle(this.renderRoot, 'z-index', '1000000');
}
private subscribeToModel(value: Model) {
if (isModalModel(value)) {
this.currentModel = value;
this.eventsModel.own(value.isOpen.subscribe(update => {
this.update(update);
}));
} else {
this.update(value === true);
}
}
private subscribeToView() {
if (this.renderRoot) {
this.eventsView.own(this.renderer.listen(this.renderRoot, 'resize', () => {
this.updatePosition();
}));
if (this.currentTarget) {
this.eventsView.own(this.renderer.listen(this.currentTarget, 'resize', () => {
this.updatePosition();
}));
this.eventsView.own(timer(100, 100).subscribe(() => {
this.updatePosition();
}));
}
}
if (this.closeAuto) {
document.addEventListener('click', this.documentClickListener, true);
this.eventsView.own(() => {
document.removeEventListener('click', this.documentClickListener);
});
}
}
private documentClickListener = (event: MouseEvent) => {
if (!event.target || this.renderRoot === null) {
return;
}
const model = this.currentModel;
if (this.closeAlways) {
setTimeout(() => {
hideModal(model);
}, 100);
} else {
try {
const rootBounds = this.renderRoot.getBoundingClientRect();
if (rootBounds.width > 0 && rootBounds.height > 0) {
const clickedInside = this.renderRoot.contains(<Node>event.target);
if (!clickedInside && this.model) {
this.model.hide();
}
}
} catch (ex) {
return;
}
}
}
private updatePosition() {
if (!this.renderRoot || !this.currentTarget) {
return;
}
const modalRect = this.renderRoot.getBoundingClientRect();
if ((modalRect.width === 0 || modalRect.height === 0) && this.position !== 'full') {
return;
}
const targetRect = this.currentTarget.getBoundingClientRect();
let y = 0;
let x = 0;
if (this.position === 'full') {
x = -this.offset + targetRect.left;
y = -this.offset + targetRect.top;
const w = 2 * this.offset + targetRect.width;
const h = 2 * this.offset + targetRect.height;
this.renderer.setStyle(this.renderRoot, 'width', `${w}px`);
this.renderer.setStyle(this.renderRoot, 'height', `${h}px`);
} else {
const viewH = document.documentElement!.clientHeight;
const viewW = document.documentElement!.clientWidth;
const position = positionModal(targetRect, modalRect, this.position, this.offset, this.autoPosition, viewW, viewH);
x = position.x;
y = position.y;
}
this.renderer.setStyle(this.renderRoot, 'top', `${y}px`);
this.renderer.setStyle(this.renderRoot, 'left', `${x}px`);
}
}
function hideModal(model: Model) {
if (model && isModalModel(model)) {
model.hide();
}
}
function isModalModel(model: Model): model is DialogModel | ModalModel {
return Types.is(model, DialogModel) || Types.is(model, ModalModel);
}

11
src/Squidex/app/framework/angular/modals/onboarding-tooltip.component.html

@ -1,6 +1,9 @@
<div *sqxModalView="tooltipModal;onRoot:true" @fade>
<div class="onboarding-rect" [sqxModalTarget]="for" [offset]="4" [autoPosition]="false" position="full"></div>
<div class="onboarding-help" [sqxModalTarget]="for" [offset]="4" [autoPosition]="false" [position]="position">
<sqx-modal [model]="tooltipModal" [target]="for" [offset]="4" position="full">
<div class="onboarding-rect"></div>
</sqx-modal>
<sqx-modal [model]="tooltipModal" [target]="for" [offset]="4">
<div class="onboarding-help" @fade>
<div class="onboarding-text">
<ng-content></ng-content>
</div>
@ -15,4 +18,4 @@
</button>
</div>
</div>
</div>
</sqx-modal>

3
src/Squidex/app/framework/angular/modals/root-view.component.html

@ -1,3 +0,0 @@
<div #element></div>
<ng-content></ng-content>

2
src/Squidex/app/framework/angular/modals/root-view.component.scss

@ -1,2 +0,0 @@
@import '_mixins';
@import '_vars';

7
src/Squidex/app/framework/angular/modals/root-view.component.ts

@ -9,8 +9,11 @@ import { ChangeDetectionStrategy, Component, ViewChild, ViewContainerRef } from
@Component({
selector: 'sqx-root-view',
styleUrls: ['./root-view.component.scss'],
templateUrl: './root-view.component.html',
template: `
<div #element></div>
<ng-content></ng-content>
`,
changeDetection: ChangeDetectionStrategy.OnPush
})
export class RootViewComponent {

5
src/Squidex/app/framework/declarations.ts

@ -36,12 +36,11 @@ export * from './angular/http/loading.interceptor';
export * from './angular/http/http-extensions';
export * from './angular/modals/dialog-renderer.component';
export * from './angular/modals/modal.component';
export * from './angular/modals/modal-dialog.component';
export * from './angular/modals/modal-target.directive';
export * from './angular/modals/modal-view.directive';
export * from './angular/modals/onboarding-tooltip.component';
export * from './angular/modals/tooltip.directive';
export * from './angular/modals/root-view.component';
export * from './angular/modals/tooltip.directive';
export * from './angular/pipes/colors.pipes';
export * from './angular/pipes/date-time.pipes';

15
src/Squidex/app/framework/module.ts

@ -58,9 +58,8 @@ import {
LoadingService,
LocalStoreService,
MessageBus,
ModalComponent,
ModalDialogComponent,
ModalTargetDirective,
ModalViewDirective,
MoneyPipe,
MonthPipe,
OnboardingService,
@ -93,10 +92,10 @@ import {
@NgModule({
imports: [
FormsModule,
ColorPickerModule,
CommonModule,
ReactiveFormsModule,
ColorPickerModule
FormsModule,
ReactiveFormsModule
],
declarations: [
AutocompleteComponent,
@ -136,9 +135,8 @@ import {
KeysPipe,
KNumberPipe,
LightenPipe,
ModalComponent,
ModalDialogComponent,
ModalTargetDirective,
ModalViewDirective,
MoneyPipe,
MonthPipe,
OnboardingTooltipComponent,
@ -204,9 +202,8 @@ import {
KeysPipe,
KNumberPipe,
LightenPipe,
ModalComponent,
ModalDialogComponent,
ModalTargetDirective,
ModalViewDirective,
MoneyPipe,
MonthPipe,
OnboardingTooltipComponent,

2
src/Squidex/app/framework/services/dialog.service.spec.ts

@ -70,7 +70,7 @@ describe('DialogService', () => {
it('should publish tooltip', () => {
const dialogService = new DialogService();
const tooltip = new Tooltip('target', 'text', 'topLeft');
const tooltip = new Tooltip('target', 'text', 'left');
let publishedTooltip: Tooltip;

13
src/Squidex/app/shared/components/asset.component.html

@ -137,9 +137,12 @@
</ng-template>
<ng-container *ngIf="asset">
<sqx-asset-dialog *sqxModalView="editDialog;onRoot:true"
[asset]="asset" [allTags]="allTags"
(cancel)="cancelEdit()"
(complete)="updateAsset($event, true)">
</sqx-asset-dialog>
<sqx-modal [model]="editDialog">
<sqx-asset-dialog
[allTags]="allTags"
[asset]="asset"
(cancel)="cancelEdit()"
(complete)="updateAsset($event, true)">
</sqx-asset-dialog>
</sqx-modal>
</ng-container>

11
src/Squidex/app/shared/components/language-selector.component.html

@ -8,9 +8,12 @@
<button type="button" class="btn btn-secondary dropdown-toggle" title="{{selectedLanguage.englishName}}" (click)="dropdown.toggle()" #button tabindex="-1">
{{selectedLanguage.iso2Code}}
</button>
<div class="dropdown-menu" *sqxModalView="dropdown;closeAlways:true" [sqxModalTarget]="button" @fade>
<div class="dropdown-item" *ngFor="let language of languages; trackBy: trackByLanguage" [class.active]="language == selectedLanguage" (click)="selectLanguage(language)">
<strong class="iso-code iso-code-dropdown">{{language.iso2Code}}</strong> ({{language.englishName}})
<sqx-modal [model]="dropdown" [target]="button" closeAlways="true">
<div class="dropdown-menu" @fade>
<div class="dropdown-item" *ngFor="let language of languages; trackBy: trackByLanguage" [class.active]="language == selectedLanguage" (click)="selectLanguage(language)">
<strong class="iso-code iso-code-dropdown">{{language.iso2Code}}</strong> ({{language.englishName}})
</div>
</div>
</div>
</sqx-modal>
</div>

4
src/Squidex/app/shared/components/markdown-editor.component.html

@ -4,8 +4,8 @@
</div>
</div>
<ng-container *sqxModalView="assetsDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="assetsDialog">
<sqx-assets-selector
(select)="insertAssets($event)">
</sqx-assets-selector>
</ng-container>
</sqx-modal>

4
src/Squidex/app/shared/components/rich-editor.component.html

@ -2,8 +2,8 @@
<div class="editor" #editor>Loading editor...</div>
</div>
<ng-container *sqxModalView="assetsDialog;onRoot:true;closeAuto:false">
<sqx-modal [model]="assetsDialog">
<sqx-assets-selector
(select)="insertAssets($event)">
</sqx-assets-selector>
</ng-container>
</sqx-modal>

62
src/Squidex/app/shared/components/search-form.component.html

@ -37,45 +37,47 @@
Search for content using full text search over all fields and languages!
</sqx-onboarding-tooltip>
<div class="dropdown-menu" *sqxModalView="searchModal;onRoot:true" [sqxModalTarget]="inputFind">
<div class="form-horizontal">
<div class="form-group row">
<label class="col-2 col-form-label" for="search">Text</label>
<sqx-modal [model]="searchModal" [target]="inputFind">
<div class="dropdown-menu">
<div class="form-horizontal">
<div class="form-group row">
<label class="col-2 col-form-label" for="search">Text</label>
<div class="col-10">
<input type="text" class="form-control" id="search" placeholder="Fulltext search"
[ngModel]="filter.fullText | async"
(ngModelChange)="filter.setFullText($event)" />
<div class="col-10">
<input type="text" class="form-control" id="search" placeholder="Fulltext search"
[ngModel]="filter.fullText | async"
(ngModelChange)="filter.setFullText($event)" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-2 col-form-label" for="filter">Filter</label>
<div class="form-group row">
<label class="col-2 col-form-label" for="filter">Filter</label>
<div class="col-10">
<input type="text" class="form-control" id="filter" placeholder="{{fieldExample}} eq [VALUE]"
[ngModel]="filter.filter | async"
(ngModelChange)="filter.setFilter($event)" />
<div class="col-10">
<input type="text" class="form-control" id="filter" placeholder="{{fieldExample}} eq [VALUE]"
[ngModel]="filter.filter | async"
(ngModelChange)="filter.setFilter($event)" />
</div>
</div>
</div>
<div class="form-group row">
<label class="col-2 col-form-label" for="orderBy">Order</label>
<div class="col-10">
<input type="text" class="form-control" id="orderBy" placeholder="{{fieldExample}} desc"
[ngModel]="filter.order | async"
(ngModelChange)="filter.setOrder($event)" />
<div class="form-group row">
<label class="col-2 col-form-label" for="orderBy">Order</label>
<div class="col-10">
<input type="text" class="form-control" id="orderBy" placeholder="{{fieldExample}} desc"
[ngModel]="filter.order | async"
(ngModelChange)="filter.setOrder($event)" />
</div>
</div>
</div>
<div class="link">
Read more about filtering in the <a href="https://docs.squidex.io/04-guides/02-api.html" sqxExternalLink>Documentation</a>.
<div class="link">
Read more about filtering in the <a href="https://docs.squidex.io/04-guides/02-api.html" sqxExternalLink>Documentation</a>.
</div>
</div>
</div>
</div>
</div>
</sqx-modal>
<ng-container *sqxModalView="saveQueryDialog;onRoot:true">
<sqx-modal [model]="saveQueryDialog">
<form [formGroup]="saveQueryForm.form" (ngSubmit)="saveQueryComplete()">
<sqx-modal-dialog (close)="saveQueryDialog.hide()">
<ng-container title>
@ -96,4 +98,4 @@
</ng-container>
</sqx-modal-dialog>
</form>
</ng-container>
</sqx-modal>

53
src/Squidex/app/shell/pages/internal/apps-menu.component.html

@ -10,31 +10,33 @@
</ng-template>
</span>
<ng-container *ngIf="appsState.apps | async; let apps">
<div class="dropdown-menu" *sqxModalView="appsMenu;closeAlways:true" @fade>
<a class="dropdown-item all-apps" routerLink="/app">
<span class="all-apps-text">All Apps</span>
<span class="all-apps-pill badge badge-pill badge-primary">{{apps.length}}</span>
</a>
<ng-container *ngIf="apps.length > 0">
<div class="dropdown-divider"></div>
<ng-container>
<sqx-modal [model]="appsMenu" closeAlways="true" *ngIf="appsState.apps | async; let apps">
<div class="dropdown-menu" @fade>
<a class="dropdown-item all-apps" routerLink="/app">
<span class="all-apps-text">All Apps</span>
<span class="all-apps-pill badge badge-pill badge-primary">{{apps.length}}</span>
</a>
<ng-container *ngIf="apps.length > 0">
<div class="dropdown-divider"></div>
<div class="apps-list">
<a class="dropdown-item" *ngFor="let app of apps; trackBy: trackByApp" [routerLink]="['/app', app.name]" routerLinkActive="active">{{app.name}}</a>
</div>
</ng-container>
<div class="apps-list">
<a class="dropdown-item" *ngFor="let app of apps; trackBy: trackByApp" [routerLink]="['/app', app.name]" routerLinkActive="active">{{app.name}}</a>
</div>
</ng-container>
<ng-container *ngIf="(uiState.settings | async).canCreateApps">
<div class="dropdown-divider"></div>
<div class="dropdown-button">
<button type="button" class="btn btn-block btn-success" (click)="addAppDialog.show()">
<i class="icon-plus"></i> Create New App
</button>
</div>
</ng-container>
</div>
<ng-container *ngIf="(uiState.settings | async).canCreateApps">
<div class="dropdown-divider"></div>
<div class="dropdown-button">
<button type="button" class="btn btn-block btn-success" (click)="addAppDialog.show()">
<i class="icon-plus"></i> Create New App
</button>
</div>
</ng-container>
</div>
</sqx-modal>
</ng-container>
</li>
@ -52,8 +54,9 @@
</ng-container>
</ul>
<ng-container *sqxModalView="addAppDialog;onRoot:true">
<sqx-modal [model]="addAppDialog">
<sqx-app-form
(complete)="addAppDialog.hide()">
</sqx-app-form>
</ng-container>
</sqx-modal>

38
src/Squidex/app/shell/pages/internal/profile-menu.component.html

@ -8,28 +8,30 @@
</span>
</span>
<div class="dropdown-menu" *sqxModalView="modalMenu;closeAlways:true" @fade>
<a class="dropdown-item dropdown-info" [sqxPopupLink]="snapshot.profileUrl">
<div>Signed in with</div>
<strong>{{snapshot.profileEmail}}</strong>
</a>
<sqx-modal [model]="modalMenu" closeAlways="true">
<div class="dropdown-menu" @fade>
<a class="dropdown-item dropdown-info" [sqxPopupLink]="snapshot.profileUrl">
<div>Signed in with</div>
<div class="dropdown-divider"></div>
<strong>{{snapshot.profileEmail}}</strong>
</a>
<div class="dropdown-divider"></div>
<a class="dropdown-item" routerLink="/app/administration" *ngIf="uiState.canUserAdminResource | async">
Administration
</a>
<a class="dropdown-item" routerLink="/app/administration" *ngIf="uiState.canUserAdminResource | async">
Administration
</a>
<a class="dropdown-item" [sqxPopupLink]="snapshot.profileUrl">
Profile
</a>
<a class="dropdown-item" [sqxPopupLink]="snapshot.profileUrl">
Profile
</a>
<div class="dropdown-divider"></div>
<div class="dropdown-divider"></div>
<a class="dropdown-item" (click)="logout()" sqxExternalLink>
Logout
</a>
</div>
<a class="dropdown-item" (click)="logout()" sqxExternalLink>
Logout
</a>
</div>
</sqx-modal>
</li>
</ul>
Loading…
Cancel
Save