mirror of https://github.com/Squidex/squidex.git
74 changed files with 747 additions and 378 deletions
@ -0,0 +1,54 @@ |
|||
// ==========================================================================
|
|||
// InstantSerializer.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using MongoDB.Bson.Serialization; |
|||
using MongoDB.Bson.Serialization.Serializers; |
|||
using NodaTime; |
|||
using NodaTime.Text; |
|||
|
|||
// ReSharper disable InvertIf
|
|||
|
|||
namespace Squidex.Infrastructure.MongoDb |
|||
{ |
|||
public sealed class InstantSerializer : SerializerBase<Instant> |
|||
{ |
|||
private static bool isRegistered; |
|||
private static readonly object LockObject = new object(); |
|||
|
|||
public static bool Register() |
|||
{ |
|||
if (!isRegistered) |
|||
{ |
|||
lock (LockObject) |
|||
{ |
|||
if (!isRegistered) |
|||
{ |
|||
BsonSerializer.RegisterSerializer(new InstantSerializer()); |
|||
|
|||
isRegistered = true; |
|||
return true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
public override Instant Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) |
|||
{ |
|||
var value = context.Reader.ReadDateTime(); |
|||
|
|||
return Instant.FromUnixTimeMilliseconds(value); |
|||
} |
|||
|
|||
public override void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Instant value) |
|||
{ |
|||
context.Writer.WriteDateTime(value.ToUnixTimeMilliseconds()); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,55 @@ |
|||
// ==========================================================================
|
|||
// InstantConverter.cs
|
|||
// Squidex Headless CMS
|
|||
// ==========================================================================
|
|||
// Copyright (c) Squidex Group
|
|||
// All rights reserved.
|
|||
// ==========================================================================
|
|||
|
|||
using System; |
|||
using Newtonsoft.Json; |
|||
using NodaTime; |
|||
using NodaTime.Text; |
|||
|
|||
// ReSharper disable ConvertIfStatementToSwitchStatement
|
|||
|
|||
namespace Squidex.Infrastructure.Json |
|||
{ |
|||
public sealed class InstantConverter : JsonConverter |
|||
{ |
|||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) |
|||
{ |
|||
if (value != null) |
|||
{ |
|||
writer.WriteValue(value.ToString()); |
|||
} |
|||
else |
|||
{ |
|||
writer.WriteNull(); |
|||
} |
|||
} |
|||
|
|||
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) |
|||
{ |
|||
if (reader.TokenType == JsonToken.String) |
|||
{ |
|||
return InstantPattern.General.Parse(reader.Value.ToString()).Value; |
|||
} |
|||
if (reader.TokenType == JsonToken.Date) |
|||
{ |
|||
return Instant.FromDateTimeUtc((DateTime)reader.Value); |
|||
} |
|||
if (reader.TokenType == JsonToken.Null && objectType == typeof(Instant?)) |
|||
{ |
|||
return null; |
|||
} |
|||
|
|||
throw new JsonException($"Not a valid date time, expected String or Date, but got {reader.TokenType}."); |
|||
} |
|||
|
|||
public override bool CanConvert(Type objectType) |
|||
{ |
|||
return objectType == typeof(Instant) || objectType == typeof(Instant?); |
|||
} |
|||
} |
|||
} |
|||
@ -1,16 +1,6 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.minlength { |
|||
&-col { |
|||
position: relative; |
|||
} |
|||
|
|||
&-label { |
|||
@include absolute(0, -.25rem, auto, auto); |
|||
} |
|||
} |
|||
|
|||
.form-check-input { |
|||
margin: 0; |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label for="field-placeholder" class="col col-3 col-form-label">Placeholder</label> |
|||
|
|||
<div class="col col-6"> |
|||
<input type="text" class="form-control" id="field-placeholder" maxlength="100" formControlName="placeholder" /> |
|||
|
|||
<span class="form-hint"> |
|||
Define the placeholder for the input control. |
|||
</span> |
|||
</div> |
|||
</div> |
|||
<div class="form-group row"> |
|||
<label for="field-editor" class="col col-3 col-form-label">Editor</label> |
|||
|
|||
<div class="col col-9"> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls.editor.value === 'Date'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="Date" /> |
|||
|
|||
<i class="icon-control-date"></i> |
|||
|
|||
<span class="radio-label">Date</span> |
|||
</label> |
|||
<label class="btn btn-radio" [class.active]="editForm.controls.editor.value === 'DateTime'"> |
|||
<input type="radio" class="radio-input" formControlName="editor" value="DateTime" /> |
|||
|
|||
<i class="icon-control-datetime"></i> |
|||
|
|||
<span class="radio-label" clas>DateTime</span> |
|||
</label> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,2 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
@ -0,0 +1,40 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input, OnInit } from '@angular/core'; |
|||
import { FormControl, FormGroup, Validators } from '@angular/forms'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { FloatConverter, NumberFieldPropertiesDto } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-date-time-ui', |
|||
styleUrls: ['date-time-ui.component.scss'], |
|||
templateUrl: 'date-time-ui.component.html' |
|||
}) |
|||
export class DateTimeUIComponent implements OnInit { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: NumberFieldPropertiesDto; |
|||
|
|||
public converter = new FloatConverter(); |
|||
|
|||
public hideAllowedValues: Observable<boolean>; |
|||
|
|||
public ngOnInit() { |
|||
this.editForm.addControl('editor', |
|||
new FormControl(this.properties.editor, [ |
|||
Validators.required |
|||
])); |
|||
this.editForm.addControl('placeholder', |
|||
new FormControl(this.properties.placeholder, [ |
|||
Validators.maxLength(100) |
|||
])); |
|||
} |
|||
} |
|||
@ -0,0 +1,33 @@ |
|||
<div [formGroup]="editForm"> |
|||
<div class="form-group row"> |
|||
<label class="col col-3 col-form-checkbox-label" for="field-required">Required</label> |
|||
|
|||
<div class="col col-6"> |
|||
<input type="checkbox" class="form-check-input" id="field-required" formControlName="isRequired" /> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col col-3 col-form-label">Min Value</label> |
|||
|
|||
<div class="col col-9"> |
|||
<sqx-date-time-editor enforceTime="true" mode="DateTime" formControlName="minValue"></sqx-date-time-editor> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row"> |
|||
<label class="col col-3 col-form-label">Max Value</label> |
|||
|
|||
<div class="col col-9"> |
|||
<sqx-date-time-editor enforceTime="true" mode="DateTime" formControlName="maxValue"></sqx-date-time-editor> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="form-group row" [class.hidden]="(hideDefaultValue | async)"> |
|||
<label class="col col-3 col-form-label" for="field-default-value">Default Value</label> |
|||
|
|||
<div class="col col-9"> |
|||
<sqx-date-time-editor enforceTime="true" formControlName="defaultValue"></sqx-date-time-editor> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
@ -0,0 +1,6 @@ |
|||
@import '_vars'; |
|||
@import '_mixins'; |
|||
|
|||
.form-check-input { |
|||
margin: 0; |
|||
} |
|||
@ -0,0 +1,49 @@ |
|||
/* |
|||
* Squidex Headless CMS |
|||
* |
|||
* @license |
|||
* Copyright (c) Sebastian Stehle. All rights reserved |
|||
*/ |
|||
|
|||
import { Component, Input, OnInit } from '@angular/core'; |
|||
import { FormControl, FormGroup } from '@angular/forms'; |
|||
import { Observable } from 'rxjs'; |
|||
|
|||
import { NumberFieldPropertiesDto, ValidatorsEx } from 'shared'; |
|||
|
|||
@Component({ |
|||
selector: 'sqx-date-time-validation', |
|||
styleUrls: ['date-time-validation.component.scss'], |
|||
templateUrl: 'date-time-validation.component.html' |
|||
}) |
|||
export class DateTimeValidationComponent implements OnInit { |
|||
@Input() |
|||
public editForm: FormGroup; |
|||
|
|||
@Input() |
|||
public properties: NumberFieldPropertiesDto; |
|||
|
|||
public hideDefaultValue: Observable<boolean>; |
|||
|
|||
public ngOnInit() { |
|||
this.editForm.addControl('maxValue', |
|||
new FormControl(this.properties.maxValue, [ |
|||
ValidatorsEx.validDateTime() |
|||
])); |
|||
|
|||
this.editForm.addControl('minValue', |
|||
new FormControl(this.properties.minValue, [ |
|||
ValidatorsEx.validDateTime() |
|||
])); |
|||
|
|||
this.editForm.addControl('defaultValue', |
|||
new FormControl(this.properties.defaultValue, [ |
|||
ValidatorsEx.validDateTime() |
|||
])); |
|||
|
|||
this.hideDefaultValue = |
|||
Observable.of(this.properties.isRequired) |
|||
.merge(this.editForm.get('isRequired').valueChanges) |
|||
.map(x => !!x); |
|||
} |
|||
} |
|||
@ -1,15 +1,10 @@ |
|||
<div> |
|||
<div class="form-inline"> |
|||
<div class="form-group date-group"> |
|||
<input type="text" class="form-control" #dateInput [disabled]="isDisabled" readonly /> |
|||
<input type="text" class="form-control" [formControl]="dateControl" (blur)="touched()" #dateInput /> |
|||
</div> |
|||
<div class="form-group time-group" *ngIf="showTime"> |
|||
<input type="text" class="form-control" [formControl]="timeControl" (blur)="touched()" /> |
|||
</div> |
|||
<div class="form-group timezone-group" *ngIf="showTimezone"> |
|||
<select class="form-control" [formControl]="timeZoneControl"> |
|||
<option *ngFor="let timezone of timezones" [ngValue]="timezone.value">{{timezone.label}}</option> |
|||
</select> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
Binary file not shown.
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Binary file not shown.
Loading…
Reference in new issue