diff --git a/src/Squidex/Squidex.csproj b/src/Squidex/Squidex.csproj
index a7ffd5aa4..bc47b99f5 100644
--- a/src/Squidex/Squidex.csproj
+++ b/src/Squidex/Squidex.csproj
@@ -22,6 +22,10 @@
+
+
+
+
PreserveNewest
@@ -81,6 +85,10 @@
+
+
+
+
<_DocumentationFile Include="$(DocumentationFile)" />
diff --git a/src/Squidex/app/framework/angular/rich-editor.component.html b/src/Squidex/app/framework/angular/rich-editor.component.html
index bb84a4048..009451124 100644
--- a/src/Squidex/app/framework/angular/rich-editor.component.html
+++ b/src/Squidex/app/framework/angular/rich-editor.component.html
@@ -1 +1,37 @@
-
\ No newline at end of file
+
+
+
\ No newline at end of file
diff --git a/src/Squidex/app/framework/angular/rich-editor.component.scss b/src/Squidex/app/framework/angular/rich-editor.component.scss
index 07b2c640b..33c03a1e5 100644
--- a/src/Squidex/app/framework/angular/rich-editor.component.scss
+++ b/src/Squidex/app/framework/angular/rich-editor.component.scss
@@ -5,4 +5,32 @@
background: $color-dark-foreground;
border: 1px solid $color-input;
height: 30rem;
+}
+.asset-selector {
+ z-index: 65560;
+
+ .modal-header {
+ background: transparent;
+ border-bottom: 1px solid #c5c5c5;
+
+ .modal-title {
+ text-decoration: none;
+ color: #333;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+ text-shadow: none;
+ }
+ }
+
+ .modal-content {
+ width: 100%;
+ border-radius: 0;
+ -webkit-border-radius: 0;
+ }
+ .modal-dialog {
+ max-width: 900px;
+ }
+
+ .btn {
+ border-radius: 0;
+ }
}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/angular/rich-editor.component.ts b/src/Squidex/app/framework/angular/rich-editor.component.ts
index 4e95a8152..cb742dc84 100644
--- a/src/Squidex/app/framework/angular/rich-editor.component.ts
+++ b/src/Squidex/app/framework/angular/rich-editor.component.ts
@@ -5,13 +5,16 @@
* Copyright (c) Sebastian Stehle. All rights reserved
*/
-import { AfterViewInit, Component, forwardRef, ElementRef, OnDestroy, ViewChild } from '@angular/core';
-import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
+import { AfterViewInit, Component, forwardRef, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder } from '@angular/forms';
import { Types } from './../utils/types';
import { ResourceLoaderService } from './../services/resource-loader.service';
+import { AppComponentBase } from './../../shared/components/app.component-base';
+import { ModalView, AppsStoreService, AssetDto, AssetsService, ImmutableArray, DialogService, AuthService, Pager } from './../../shared/declarations-base';
+
declare var tinymce: any;
export const SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
@@ -24,20 +27,42 @@ export const SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
templateUrl: './rich-editor.component.html',
providers: [SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR]
})
-export class RichEditorComponent implements ControlValueAccessor, AfterViewInit, OnDestroy {
+export class RichEditorComponent extends AppComponentBase implements ControlValueAccessor, AfterViewInit, OnDestroy, OnInit {
private callChange = (v: any) => { /* NOOP */ };
private callTouched = () => { /* NOOP */ };
private tinyEditor: any;
private tinyInitTimer: any;
private value: string;
private isDisabled = false;
+ public assetsItems: ImmutableArray;
+ public assetsPager = new Pager(0, 0, 12);
@ViewChild('editor')
public editor: ElementRef;
- constructor(
- private readonly resourceLoader: ResourceLoaderService
+ public assetsDialog = new ModalView();
+ public assetsForm = this.formBuilder.group({
+ name: ['']
+ });
+
+ constructor(dialogs: DialogService, apps: AppsStoreService, authService: AuthService,
+ private readonly resourceLoader: ResourceLoaderService,
+ private readonly formBuilder: FormBuilder,
+ private readonly assetsService: AssetsService
) {
+ super(dialogs, apps, authService);
+ }
+
+ public ngOnInit() {
+
+ this.appNameOnce()
+ .switchMap(app => this.assetsService.getAssets(app, this.assetsPager.pageSize, this.assetsPager.skip))
+ .subscribe(dtos => {
+ this.assetsItems = ImmutableArray.of(dtos.items);
+ this.assetsPager = this.assetsPager.setCount(dtos.total);
+ }, error => {
+ this.notifyError(error);
+ });
}
public ngOnDestroy() {
@@ -74,7 +99,9 @@ export class RichEditorComponent implements ControlValueAccessor, AfterViewInit,
self.tinyEditor.setContent(this.value || '');
}, 500);
},
- removed_menuitems: 'newdocument', plugins: 'code', target: this.editor.nativeElement
+ removed_menuitems: 'newdocument', plugins: 'code,image', target: this.editor.nativeElement, file_picker_types: 'image', file_picker_callback: (cb: any, value: any, meta: any) => {
+ self.assetsDialog.show();
+ }
});
});
}
@@ -102,4 +129,13 @@ export class RichEditorComponent implements ControlValueAccessor, AfterViewInit,
public registerOnTouched(fn: any) {
this.callTouched = fn;
}
+
+ public selecteAsset() {
+ console.log('Selecting asset ' + this.assetsForm.controls['name'].value);
+ }
+
+ public cancelSelectAsset() {
+ console.log('asset selection canceled');
+ this.assetsDialog.hide();
+ }
}
\ No newline at end of file
diff --git a/src/Squidex/app/framework/declarations.ts b/src/Squidex/app/framework/declarations.ts
index 40c8b1d87..188559d86 100644
--- a/src/Squidex/app/framework/declarations.ts
+++ b/src/Squidex/app/framework/declarations.ts
@@ -36,7 +36,7 @@ export * from './angular/panel-container.directive';
export * from './angular/parent-link.directive';
export * from './angular/popup-link.directive';
export * from './angular/progress-bar.component';
-export * from './angular/rich-editor.component';
+// export * from './angular/rich-editor.component';
export * from './angular/root-view.directive';
export * from './angular/router-utils';
export * from './angular/scroll-active.directive';
diff --git a/src/Squidex/app/framework/module.ts b/src/Squidex/app/framework/module.ts
index 973635904..c23309878 100644
--- a/src/Squidex/app/framework/module.ts
+++ b/src/Squidex/app/framework/module.ts
@@ -54,7 +54,7 @@ import {
PopupLinkDirective,
ProgressBarComponent,
ResourceLoaderService,
- RichEditorComponent,
+ // RichEditorComponent,
RootViewDirective,
RootViewService,
ScrollActiveDirective,
@@ -115,7 +115,7 @@ import {
ParentLinkDirective,
PopupLinkDirective,
ProgressBarComponent,
- RichEditorComponent,
+ // RichEditorComponent,
RootViewDirective,
ScrollActiveDirective,
ShortcutComponent,
@@ -164,7 +164,7 @@ import {
ParentLinkDirective,
PopupLinkDirective,
ProgressBarComponent,
- RichEditorComponent,
+ // RichEditorComponent,
RootViewDirective,
ScrollActiveDirective,
ShortcutComponent,
diff --git a/src/Squidex/app/shared/components/asset.component.html b/src/Squidex/app/shared/components/asset.component.html
index 88fc97799..96e1f7633 100644
--- a/src/Squidex/app/shared/components/asset.component.html
+++ b/src/Squidex/app/shared/components/asset.component.html
@@ -1,4 +1,4 @@
-
+
diff --git a/src/Squidex/app/shared/components/asset.component.ts b/src/Squidex/app/shared/components/asset.component.ts
index 85540c6cf..d559efba6 100644
--- a/src/Squidex/app/shared/components/asset.component.ts
+++ b/src/Squidex/app/shared/components/asset.component.ts
@@ -56,6 +56,9 @@ export class AssetComponent extends AppComponentBase implements OnInit {
@Output()
public deleting = new EventEmitter();
+ @Output()
+ public clicked = new EventEmitter();
+
@Output()
public failed = new EventEmitter();
diff --git a/src/Squidex/app/shared/components/declarations.ts b/src/Squidex/app/shared/components/declarations.ts
new file mode 100644
index 000000000..40c8b1d87
--- /dev/null
+++ b/src/Squidex/app/shared/components/declarations.ts
@@ -0,0 +1,76 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+export * from './angular/animations';
+export * from './angular/autocomplete.component';
+export * from './angular/can-deactivate.guard';
+export * from './angular/confirm-click.directive';
+export * from './angular/control-errors.component';
+export * from './angular/copy.directive';
+export * from './angular/date-time-editor.component';
+export * from './angular/date-time.pipes';
+export * from './angular/dialog-renderer.component';
+export * from './angular/dropdown.component';
+export * from './angular/file-drop.directive';
+export * from './angular/focus-on-init.directive';
+export * from './angular/geolocation-editor.component';
+export * from './angular/http-extensions-impl';
+export * from './angular/image-source.directive';
+export * from './angular/indeterminate-value.directive';
+export * from './angular/jscript-editor.component';
+export * from './angular/json-editor.component';
+export * from './angular/lowercase-input.directive';
+export * from './angular/markdown-editor.component';
+export * from './angular/modal-target.directive';
+export * from './angular/modal-view.directive';
+export * from './angular/money.pipe';
+export * from './angular/name.pipe';
+export * from './angular/numbers.pipes';
+export * from './angular/onboarding-tooltip.component';
+export * from './angular/panel.component';
+export * from './angular/panel-container.directive';
+export * from './angular/parent-link.directive';
+export * from './angular/popup-link.directive';
+export * from './angular/progress-bar.component';
+export * from './angular/rich-editor.component';
+export * from './angular/root-view.directive';
+export * from './angular/router-utils';
+export * from './angular/scroll-active.directive';
+export * from './angular/shortcut.component';
+export * from './angular/slider.component';
+export * from './angular/sorted.directive';
+export * from './angular/stars.component';
+export * from './angular/tag-editor.component';
+export * from './angular/template-wrapper.directive';
+export * from './angular/title.component';
+export * from './angular/toggle.component';
+export * from './angular/user-report.component';
+export * from './angular/validators';
+export * from './configurations';
+
+export * from './services/analytics.service';
+export * from './services/clipboard.service';
+export * from './services/dialog.service';
+export * from './services/local-store.service';
+export * from './services/local-cache.service';
+export * from './services/message-bus.service';
+export * from './services/onboarding.service';
+export * from './services/resource-loader.service';
+export * from './services/root-view.service';
+export * from './services/shortcut.service';
+export * from './services/title.service';
+
+export * from './utils/date-helper';
+export * from './utils/date-time';
+export * from './utils/duration';
+export * from './utils/immutable-array';
+export * from './utils/math-helper';
+export * from './utils/modal-view';
+export * from './utils/pager';
+export * from './utils/string-helper';
+export * from './utils/types';
+export * from './utils/version';
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/rich-editor.component.html b/src/Squidex/app/shared/components/rich-editor.component.html
new file mode 100644
index 000000000..2a0f03b4b
--- /dev/null
+++ b/src/Squidex/app/shared/components/rich-editor.component.html
@@ -0,0 +1,29 @@
+
+
+
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/rich-editor.component.scss b/src/Squidex/app/shared/components/rich-editor.component.scss
new file mode 100644
index 000000000..33c03a1e5
--- /dev/null
+++ b/src/Squidex/app/shared/components/rich-editor.component.scss
@@ -0,0 +1,36 @@
+@import '_mixins';
+@import '_vars';
+
+.editor {
+ background: $color-dark-foreground;
+ border: 1px solid $color-input;
+ height: 30rem;
+}
+.asset-selector {
+ z-index: 65560;
+
+ .modal-header {
+ background: transparent;
+ border-bottom: 1px solid #c5c5c5;
+
+ .modal-title {
+ text-decoration: none;
+ color: #333;
+ font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
+ text-shadow: none;
+ }
+ }
+
+ .modal-content {
+ width: 100%;
+ border-radius: 0;
+ -webkit-border-radius: 0;
+ }
+ .modal-dialog {
+ max-width: 900px;
+ }
+
+ .btn {
+ border-radius: 0;
+ }
+}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/components/rich-editor.component.ts b/src/Squidex/app/shared/components/rich-editor.component.ts
new file mode 100644
index 000000000..ed8714654
--- /dev/null
+++ b/src/Squidex/app/shared/components/rich-editor.component.ts
@@ -0,0 +1,143 @@
+/*
+ * Squidex Headless CMS
+ *
+ * @license
+ * Copyright (c) Sebastian Stehle. All rights reserved
+ */
+
+import { AfterViewInit, Component, forwardRef, ElementRef, OnDestroy, ViewChild } from '@angular/core';
+import { ControlValueAccessor, NG_VALUE_ACCESSOR, FormBuilder } from '@angular/forms';
+
+import { Types, ResourceLoaderService } from 'framework';
+import { AppComponentBase } from './app.component-base';
+import { ModalView, AppsStoreService, AssetDto, AssetsService, ImmutableArray, DialogService, AuthService, Pager } from './../declarations-base';
+
+declare var tinymce: any;
+
+export const SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR: any = {
+ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => RichEditorComponent), multi: true
+};
+
+@Component({
+ selector: 'sqx-rich-editor',
+ styleUrls: ['./rich-editor.component.scss'],
+ templateUrl: './rich-editor.component.html',
+ providers: [SQX_RICH_EDITOR_CONTROL_VALUE_ACCESSOR]
+})
+export class RichEditorComponent extends AppComponentBase implements ControlValueAccessor, AfterViewInit, OnDestroy {
+ private callChange = (v: any) => { /* NOOP */ };
+ private callTouched = () => { /* NOOP */ };
+ private tinyEditor: any;
+ private tinyInitTimer: any;
+ private value: string;
+ private isDisabled = false;
+ public assetsItems: ImmutableArray;
+ public assetsPager = new Pager(0, 0, 12);
+
+ @ViewChild('editor')
+ public editor: ElementRef;
+
+ public assetsDialog = new ModalView();
+ public assetsForm = this.formBuilder.group({
+ name: ['']
+ });
+
+ constructor(dialogs: DialogService, apps: AppsStoreService, authService: AuthService,
+ private readonly resourceLoader: ResourceLoaderService,
+ private readonly formBuilder: FormBuilder,
+ private readonly assetsService: AssetsService
+ ) {
+ super(dialogs, apps, authService);
+ }
+
+ private load() {
+ this.appNameOnce()
+ .switchMap(app => this.assetsService.getAssets(app, this.assetsPager.pageSize, this.assetsPager.skip))
+ .subscribe(dtos => {
+ this.assetsItems = ImmutableArray.of(dtos.items);
+ this.assetsPager = this.assetsPager.setCount(dtos.total);
+ }, error => {
+ this.notifyError(error);
+ });
+ }
+
+ public ngOnDestroy() {
+ clearTimeout(this.tinyInitTimer);
+
+ tinymce.remove(this.editor);
+ }
+
+ public ngAfterViewInit() {
+ const self = this;
+
+ this.resourceLoader.loadScript('https://cdnjs.cloudflare.com/ajax/libs/tinymce/4.5.4/tinymce.min.js').then(() => {
+ tinymce.init({
+ setup: (editor: any) => {
+ self.tinyEditor = editor;
+ self.tinyEditor.setMode(this.isDisabled ? 'readonly' : 'design');
+
+ self.tinyEditor.on('change', () => {
+ const value = editor.getContent();
+
+ if (this.value !== value) {
+ this.value = value;
+
+ self.callChange(value);
+ }
+ });
+
+ self.tinyEditor.on('blur', () => {
+ self.callTouched();
+ });
+
+ this.tinyInitTimer =
+ setTimeout(() => {
+ self.tinyEditor.setContent(this.value || '');
+ }, 500);
+ },
+ removed_menuitems: 'newdocument', plugins: 'code,image', target: this.editor.nativeElement, file_picker_types: 'image', file_picker_callback: (cb: any, value: any, meta: any) => {
+ self.load();
+ self.assetsDialog.show();
+ }
+ });
+ });
+ }
+
+ public writeValue(value: string) {
+ this.value = Types.isString(value) ? value : '';
+
+ if (this.tinyEditor) {
+ this.tinyEditor.setContent(this.value);
+ }
+ }
+
+ public setDisabledState(isDisabled: boolean): void {
+ this.isDisabled = isDisabled;
+
+ if (this.tinyEditor) {
+ this.tinyEditor.setMode(isDisabled ? 'readonly' : 'design');
+ }
+ }
+
+ public registerOnChange(fn: any) {
+ this.callChange = fn;
+ }
+
+ public registerOnTouched(fn: any) {
+ this.callTouched = fn;
+ }
+
+ public selecteAsset() {
+ console.log('Selecting asset ' + this.assetsForm.controls['name'].value);
+ }
+
+ public cancelSelectAsset() {
+ console.log('asset selection canceled');
+ this.assetsDialog.hide();
+ }
+
+ public onAssetClicked(asset: AssetDto) {
+ console.log('Asset clicked on');
+ console.log(asset);
+ }
+}
\ No newline at end of file
diff --git a/src/Squidex/app/shared/declarations.ts b/src/Squidex/app/shared/declarations.ts
index 3e4313916..5fc29bd25 100644
--- a/src/Squidex/app/shared/declarations.ts
+++ b/src/Squidex/app/shared/declarations.ts
@@ -13,5 +13,6 @@ export * from './components/help.component';
export * from './components/history.component';
export * from './components/language-selector.component';
export * from './components/pipes';
+export * from './components/rich-editor.component';
export * from './declarations-base';
\ No newline at end of file
diff --git a/src/Squidex/app/shared/module.ts b/src/Squidex/app/shared/module.ts
index f67368770..6f229df77 100644
--- a/src/Squidex/app/shared/module.ts
+++ b/src/Squidex/app/shared/module.ts
@@ -57,7 +57,8 @@ import {
UserManagementService,
UsersProviderService,
UsersService,
- WebhooksService
+ WebhooksService,
+ RichEditorComponent
} from './declarations';
@NgModule({
@@ -81,7 +82,8 @@ import {
UserNamePipe,
UserNameRefPipe,
UserPicturePipe,
- UserPictureRefPipe
+ UserPictureRefPipe,
+ RichEditorComponent
],
exports: [
AppFormComponent,
@@ -99,7 +101,8 @@ import {
UserNamePipe,
UserNameRefPipe,
UserPicturePipe,
- UserPictureRefPipe
+ UserPictureRefPipe,
+ RichEditorComponent
]
})
export class SqxSharedModule {
diff --git a/src/Squidex/appsettings.json b/src/Squidex/appsettings.json
index eec0956f2..5d3319bce 100644
--- a/src/Squidex/appsettings.json
+++ b/src/Squidex/appsettings.json
@@ -3,7 +3,7 @@
/*
* Set the base url of your application, to generate correct urls in background process.
*/
- "baseUrl": "http://localhost:5000"
+ "baseUrl": "http://localhost:59777"
},
"ui": {
@@ -154,7 +154,7 @@
*
* Read More: https://docs.mongodb.com/manual/reference/connection-string/
*/
- "configuration": "mongodb://localhost",
+ "configuration": "mongodb://localhost:27017",
/*
* The database for all your content collections (one collection per app).
*/
@@ -171,21 +171,23 @@
* Enable password auth.
*/
"allowPasswordAuth": true,
+ "adminEmail": "sow@orderboxmedia.com",
+ "adminPassword": "Admin!@#123",
/*
- * Settings for Google auth (keep empty to disable).
+ * Settings for Google auth (keep empty to disable).1
*/
- "googleClient": "1006817248705-t3lb3ge808m9am4t7upqth79hulk456l.apps.googleusercontent.com",
- "googleSecret": "QsEi-fHqkGw2_PjJmtNHf2wg",
+ "googleClient": "",
+ "googleSecret": "",
/*
* Settings for Github auth (keep empty to disable).
*/
- "githubClient": "211ea00e726baf754c78",
- "githubSecret": "d0a0d0fe2c26469ae20987ac265b3a339fd73132",
+ "githubClient": "",
+ "githubSecret": "",
/*
* Settings for Microsoft auth (keep empty to disable).
*/
- "microsoftClient": "b55da740-6648-4502-8746-b9003f29d5f1",
- "microsoftSecret": "idWbANxNYEF4cB368WXJhjN",
+ "microsoftClient": "",
+ "microsoftSecret": "",
/*
* Lock new users automatically, the administrator must unlock them.
*/