first commit

This commit is contained in:
2024-04-19 12:53:45 +07:00
commit 71a3a661dc
1943 changed files with 246917 additions and 0 deletions

View File

@@ -0,0 +1,159 @@
:host ::ng-deep .btn-light:not(:disabled):not(.disabled):active {
color: unset !important;
background-color: unset !important;
border-color: #d3d9df !important;
}
:host ::ng-deep .btn-light:hover:not(.disabled):active {
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
:host ::ng-deep .btn-light {
color: unset !important;
background-color: unset !important;
border-color: unset !important;
}
:host ::ng-deep .bg-primary {
background-color: #007bff !important;
}
:host ::ng-deep .text-white {
color: #fff !important;
}
:host ::ng-deep .custom-day {
text-align: center;
padding: .185rem .25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
:host ::ng-deep .custom-day:active {
color: #6d7183 !important;
background-color: #fff !important;
border-block-color: rgb(2, 117, 216) !important;
}
.bg-light {
background-color: #f8f9fa !important;
}
:host ::ng-deep .hidden {
display: block !important;
}
.ngb-dp-weekday {
color: #17a2b8;
}
.ngb-dp-week-number,
.ngb-dp-weekday {
line-height: 2rem;
text-align: center;
font-style: italic;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.small {
font-size: 80%;
font-weight: 400;
}
.ngb-dp-day {
cursor: pointer !important;
}
.ngb-dp-month {
pointer-events: none;
}
.btn-light:hover {
color: #212529 !important;
background-color: #e2e6ea !important;
border-color: #dae0e5 !important;
}
.ngb-datepicker-month-view {
pointer-events: auto;
}
.ngb-dp-header {
border-bottom: 0;
border-radius: .25rem .25rem 0 0;
padding-top: .25rem;
}
.ngb-dp-day,
.ngb-dp-week-number,
.ngb-dp-weekday {
width: 2rem;
height: 2rem;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
display: inline-block;
height: 2rem;
width: 2rem;
}
.custom-day.focused {
background-color: #e6e6e6;
}
.custom-day.range,
.custom-day:hover {
background-color: rgb(2, 117, 216);
color: white;
}
.custom-day.faded {
background-color: rgba(2, 117, 216, 0.5);
}
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}
.custom-day {
text-align: center;
padding: 0.185rem 0.25rem;
border-radius: 0.25rem;
display: inline-block;
width: 2rem;
}
.custom-day:hover,
.custom-day.focused {
background-color: #e6e6e6;
}
.weekend {
background-color: #f0ad4e;
border-radius: 1rem;
color: white;
}
.hidden {
display: none;
}
:host ::ng-deep .ngb-dp-header {
background-color: var(--light) !important;
}
:host ::ng-deep .ngb-dp-weekdays {
background-color: var(--light);
}
:host ::ng-deep .ngb-dp-month-name {
background-color: var(--light);
}

View File

@@ -0,0 +1,323 @@
<div class="app-content content" >
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="row">
<div class="col-12 mt-3 mb-1">
<h4 class="text-uppercase">Date Picker</h4>
</div>
</div>
<section id="datePicker">
<div class="row" matchHeight="card">
<div class="col-lg-12 col-xl-6" *blockUI="'simpleDatepicker'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadSimpleDatepicker($event)">
<ng-container mCardHeaderTitle>
Simple datepicker
</ng-container>
<ng-container mCardBody>
<ngb-datepicker #dp [(ngModel)]="model" (navigate)="date = $event.next"></ngb-datepicker>
<div class="block mt-1 mb-3">
<button class="btn btn-sm btn-outline-primary mr-1" (click)="dp.navigateTo({year: 2013, month: 2})">To
Feb 2013</button>
<button class="btn btn-sm btn-outline-primary mr-1" (click)="dp.navigateTo()">To current
month</button>
<button class="btn btn-sm btn-outline-primary mr-1" (click)="selectToday()">Select Today</button>
</div>
<p>Month: {{ date.month }}.{{ date.year }}</p>
<p>Model: {{ model | json }}</p>
</ng-container>
</m-card>
</div>
<div class="col-lg-12 col-xl-6" *blockUI="'disableDatepicker'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadDisableDatepicker($event)">
<ng-container mCardHeaderTitle>
Disabled datepicker
</ng-container>
<ng-container mCardBody>
<ngb-datepicker [(ngModel)]="disabledModel" [disabled]="disabled"></ngb-datepicker>
<div class="mt-1">
<button class="btn btn-sm btn-outline-{{disabled ? 'danger' : 'success'}}"
(click)="disabled = !disabled">
{{ disabled ? "disabled" : "enabled"}}
</button>
</div>
</ng-container>
</m-card>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-lg-12 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Datepicker in a popup</h4>
</div>
<div class="card-content">
<div class="card-body">
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd" name="dp" [(ngModel)]="popupModel"
ngbDatepicker #d2="ngbDatepicker">
<div class="input-group-append">
<div class="input-group-text" (click)="d2.toggle()">
<i class="fa fa-calendar" style="cursor: pointer;"></i>
</div>
</div>
</div>
</div>
</form>
<p class="mt-4">Model: {{ popupModel | json }}</p>
</div>
</div>
</div>
</div>
<div class="col-lg-12 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Custom day view</h4>
</div>
<div class="card-content">
<div class="card-body">
<p>This datepicker uses a custom template to display days. All week-ends are displayed with an orange
background.</p>
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd" name="dp" [(ngModel)]="model" ngbDatepicker
[dayTemplate]="customDay" [markDisabled]="isDisabled" #d3="ngbDatepicker">
<div class="input-group-append">
<div class="input-group-text" (click)="d3.toggle()">
<i class="fa fa-calendar" style="cursor: pointer;"></i>
</div>
</div>
</div>
</div>
</form>
<ng-template #customDay let-date="date" let-currentMonth="currentMonth" let-selected="selected"
let-disabled="disabled" let-focused="focused">
<span class="custom-day" [class.weekend]="isWeekend(date)"
[class.hidden]="date.month !== currentMonth" [class.text-muted]="disabled">
{{ date.day }}
</span>
</ng-template>
</div>
</div>
</div>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-lg-12 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Multiple months</h4>
</div>
<div class="card-content">
<div class="card-body" fxFlex="auto" [perfectScrollbar]="config">
<ngb-datepicker [displayMonths]="displayMonths" [navigation]="navigation"></ngb-datepicker>
<p class="pt-1">Inline</p>
<form class="form-inline">
<div class="form-group">
<div class="input-group">
<input class="form-control" placeholder="yyyy-mm-dd" name="dp" [displayMonths]="displayMonths"
[navigation]="navigation" ngbDatepicker #d="ngbDatepicker">
<div class="input-group-append">
<div class="input-group-text" (click)="d.toggle()">
<i class="fa fa-calendar" style="cursor: pointer;"></i>
</div>
</div>
</div>
</div>
</form>
<p class="pt-1">Options</p>
<select class="custom-select" [(ngModel)]="displayMonths">
<option [ngValue]="1">One month</option>
<option [ngValue]="2">Two months</option>
</select>
<select class="custom-select" [(ngModel)]="navigation">
<option value="none">Without navigation</option>
<option value="select">With select boxes</option>
<option value="arrows">Without select boxes</option>
</select>
</div>
</div>
</div>
</div>
<div class="col-lg-12 col-xl-6">
<div class="card">
<div class="card-header">
<h4 class="card-title">Range Date Picker</h4>
</div>
<div class="card-content">
<div class="card-body" fxFlex="auto" [perfectScrollbar]="config">
<ngb-datepicker #dp1111 ngModel (ngModelChange)="onDateChange($event)" [displayMonths]="2"
[dayTemplate]="t" outsideDays="hidden">
</ngb-datepicker>
<ng-template #t let-date let-focused="focused">
<span class="custom-day" [class.focused]="focused" [class.range]="isRange(date)"
[class.faded]="isHovered(date) || isInside(date)" (mouseenter)="hoveredDate = date"
(mouseleave)="hoveredDate = null">
{{ date.day }}
</span>
</ng-template>
<hr>
<div class="row">
<div class="col-12 col-md-6">
<p>From: {{ fromDate | json }} </p>
</div>
<div class="col-12 col-md-6">
<p>To: {{ toDate | json }} </p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<div class="row">
<div class="col-12 mt-3 mb-1">
<h4 class="text-uppercase">Time Picker</h4>
</div>
</div>
<section id="timePicker">
<div class="row" matchHeight="card">
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Basic Timepicker</h4>
</div>
<div class="card-content">
<div class="card-body">
<ngb-timepicker [(ngModel)]="time"></ngb-timepicker>
<hr>
<p>Selected time: {{time | json}}</p>
</div>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Meridian</h4>
</div>
<div class="card-content">
<div class="card-body">
<ngb-timepicker [(ngModel)]="meridianTime" [meridian]="meridian"></ngb-timepicker>
<button class="btn btn-outline-{{meridian ? 'success' : 'danger'}} mb-3 mt-3"
(click)="toggleMeridian()">
Meridian - {{meridian ? "ON" : "OFF"}}
</button>
<hr>
<p>Selected time: {{meridianTime | json}}</p>
</div>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Seconds</h4>
</div>
<div class="card-content">
<div class="card-body">
<ngb-timepicker [(ngModel)]="secondsTime" [seconds]="seconds"></ngb-timepicker>
<button class="btn btn-outline-{{seconds ? 'success' : 'danger'}} mb-3 mt-3" (click)="toggleSeconds()">
Seconds - {{seconds ? "ON" : "OFF"}}
</button>
<hr>
<p>Selected time: {{secondsTime | json}}</p>
</div>
</div>
</div>
</div>
</div>
<div class="row" matchHeight="card">
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Spinners</h4>
</div>
<div class="card-content">
<div class="card-body">
<p>This datepicker uses a custom template to display days. All week-ends are displayed with an orange
background.</p>
<ngb-timepicker [(ngModel)]="spinnersTime" [spinners]="spinners"></ngb-timepicker>
<button class="m-t-1 btn btn-outline-{{spinners ? 'success' : 'danger'}} mb-3 mt-3"
(click)="toggleSpinners()">
Spinners - {{spinners ? "ON" : "OFF"}}
</button>
</div>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Custom steps</h4>
</div>
<div class="card-content">
<div class="card-body">
<ngb-timepicker [(ngModel)]="stepsTime" [seconds]="true" [hourStep]="hourStep" [minuteStep]="minuteStep"
[secondStep]="secondStep"></ngb-timepicker>
<div class="row">
<div class="col-sm-3">
<label for="changeHourStep">Hour Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="hourStep" />
</div>
<div class="col-sm-3">
<label for="changeMinuteStep">Minute Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="minuteStep" />
</div>
<div class="col-sm-4">
<label for="changeSecondStep">Second Step</label>
<input type="number" class="form-control form-control-sm" [(ngModel)]="secondStep" />
</div>
</div>
<hr>
<p>Selected time: {{stepsTime | json}}</p>
</div>
</div>
</div>
</div>
<div class="col-md-4 col-lg-4">
<div class="card">
<div class="card-header">
<h4 class="card-title">Custom validation</h4>
</div>
<div class="card-content">
<div class="card-body">
<p>Illustrates custom validation, you have to select time between 12:00 and 13:59</p>
<div class="form-group" [class.has-success]="ctrl.valid" [class.has-danger]="!ctrl.valid">
<ngb-timepicker [(ngModel)]="validationTime" [formControl]="ctrl" required></ngb-timepicker>
<div class="form-control-feedback">
<div *ngIf="ctrl.valid">Great choice</div>
<div *ngIf="ctrl.errors && ctrl.errors['required']">Select some time during lunchtime</div>
<div *ngIf="ctrl.errors && ctrl.errors['tooLate']">Oh no, it's way too late</div>
<div *ngIf="ctrl.errors && ctrl.errors['tooEarly']">It's a bit too early</div>
</div>
</div>
<hr>
<p>Selected time: {{validationTime | json}}</p>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { DateTimePickerComponent } from './date-time-picker.component';
describe('DateTimePickerComponent', () => {
let component: DateTimePickerComponent;
let fixture: ComponentFixture<DateTimePickerComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ DateTimePickerComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(DateTimePickerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,198 @@
import { Component, OnInit, ViewChild } from '@angular/core';
import { NgbDateStruct, NgbTimeStruct, NgbDate } from '@ng-bootstrap/ng-bootstrap';
import { FormControl } from '@angular/forms';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { PerfectScrollbarConfigInterface, PerfectScrollbarComponent, PerfectScrollbarDirective } from 'ngx-perfect-scrollbar';
const now = new Date();
const I18N_VALUES = {
en: {
weekdays: ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'],
months: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],
},
};
// Range datepicker Start
const equals = (one: NgbDateStruct, two: NgbDateStruct) =>
one && two && two.year === one.year && two.month === one.month && two.day === one.day;
const before = (one: NgbDateStruct, two: NgbDateStruct) =>
!one || !two ? false : one.year === two.year ? one.month === two.month ? one.day === two.day
? false : one.day < two.day : one.month < two.month : one.year < two.year;
const after = (one: NgbDateStruct, two: NgbDateStruct) =>
!one || !two ? false : one.year === two.year ? one.month === two.month ? one.day === two.day
? false : one.day > two.day : one.month > two.month : one.year > two.year;
// Range datepicker Ends
@Component({
selector: 'app-date-time-picker',
templateUrl: './date-time-picker.component.html',
styleUrls: ['./date-time-picker.component.css']
})
export class DateTimePickerComponent implements OnInit {
@BlockUI('simpleDatepicker') blockUISimpleDatepicker: NgBlockUI;
@BlockUI('disableDatepicker') blockUIDisableDatepicker: NgBlockUI;
public config: PerfectScrollbarConfigInterface = { };
@ViewChild(PerfectScrollbarComponent) componentRef?: PerfectScrollbarComponent;
@ViewChild(PerfectScrollbarDirective, { static: true }) directiveRef?: PerfectScrollbarDirective;
public breadcrumb: any;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
// datePicker Variable declaration
d: any;
d2: any;
d3: any;
model: NgbDateStruct;
popupModel;
date: { year: number, month: number };
displayMonths = 2;
navigation = 'select';
disabledModel: NgbDateStruct = { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };
disabled = true;
customModel: NgbDateStruct;
// timePicker Variable declaration
meridian = true;
time: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
meridianTime: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
secondsTime: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
spinnersTime: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
stepsTime: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
validationTime: NgbTimeStruct = { hour: 13, minute: 30, second: 30 };
seconds = true;
spinners = true;
hourStep = 1;
minuteStep = 15;
secondStep = 30;
configModal; // Global configuration of datepickers
// Range datepicker start
hoveredDate: NgbDateStruct;
fromDate: NgbDateStruct;
toDate: NgbDateStruct;
// timePicker code
ctrl = new FormControl('', (control: FormControl) => {
const value = control.value;
if (!value) {
return null;
}
if (value.hour < 12) {
return { tooEarly: true };
}
if (value.hour > 13) {
return { tooLate: true };
}
return null;
});
// Range datepicker starts
onDateChange(date: NgbDateStruct) {
if (!this.fromDate && !this.toDate) {
this.fromDate = date;
} else if (this.fromDate && !this.toDate && after(date, this.fromDate)) {
this.toDate = date;
} else {
this.toDate = null;
this.fromDate = date;
}
}
isHovered = date => this.fromDate && !this.toDate && this.hoveredDate && after(date, this.fromDate) && before(date, this.hoveredDate);
isInside = date => after(date, this.fromDate) && before(date, this.toDate);
isFrom = date => equals(date, this.fromDate);
isTo = date => equals(date, this.toDate);
// Range datepicker ends
// Selects today's date
selectToday() {
this.model = { year: now.getFullYear(), month: now.getMonth() + 1, day: now.getDate() };
}
// Custom Day View Starts
isWeekend(date: NgbDateStruct) {
const d = new Date(date.year, date.month - 1, date.day);
return d.getDay() === 0 || d.getDay() === 6;
}
isDisabled(date: NgbDateStruct, current: { month: number }) {
return date.month !== current.month;
}
// Custom Day View Ends
isRange(date: NgbDate) {
return date.equals(this.fromDate) || date.equals(this.toDate) || this.isInside(date) || this.isHovered(date);
}
// Using for Meridian
toggleMeridian() {
this.meridian = !this.meridian;
}
// Using for Seconds
toggleSeconds() {
this.seconds = !this.seconds;
}
// Using for Spinners
toggleSpinners() {
this.spinners = !this.spinners;
}
ngOnInit() {
this.selectToday();
this.breadcrumb = {
'mainlabel': 'Date Time Picker',
'links': [
{
'name': 'Home',
'isLink': true,
'link': '/dashboard/sales'
},
{
'name': 'Extra Components',
'isLink': true,
'link': '#'
},
{
'name': 'Date Time Picker',
'isLink': false
}
]
};
}
reloadSimpleDatepicker() {
this.blockUISimpleDatepicker.start('Loading..');
setTimeout(() => {
this.blockUISimpleDatepicker.stop();
}, 2500);
}
reloadDisableDatepicker() {
this.blockUIDisableDatepicker.start('Loading..');
setTimeout(() => {
this.blockUIDisableDatepicker.stop();
}, 2500);
}
}

View File

@@ -0,0 +1,52 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { DateTimePickerComponent } from './date-time-picker/date-time-picker.component';
import { RouterModule } from '@angular/router';
import { NgbModule } from '@ng-bootstrap/ng-bootstrap';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { TypeAheadComponent } from './type-ahead/type-ahead.component';
import { MatchHeightModule } from '../partials/general/match-height/match-height.module';
import { BreadcrumbModule } from 'src/app/_layout/breadcrumb/breadcrumb.module';
import { CustomFormsModule } from 'ngx-custom-validators';
import { ArchwizardModule } from 'angular-archwizard';
import { BlockUIModule } from 'ng-block-ui';
import { QuillModule } from 'ngx-quill';
import { BlockTemplateComponent } from 'src/app/_layout/blockui/block-template.component';
import { CardModule } from '../partials/general/card/card.module';
import { TextEditorComponent } from './text-editor/text-editor.component';
import { PerfectScrollbarModule } from 'ngx-perfect-scrollbar';
@NgModule({
imports: [
CommonModule,
FormsModule,
CardModule,
ReactiveFormsModule,
MatchHeightModule,
BreadcrumbModule,
ArchwizardModule,
CustomFormsModule,
NgbModule,
QuillModule.forRoot(),
PerfectScrollbarModule,
BlockUIModule.forRoot({
template: BlockTemplateComponent
}),
RouterModule.forChild([
{
path: 'dateTimePicker',
component: DateTimePickerComponent
},
{
path: 'typeAhead',
component: TypeAheadComponent
},
{
path: 'text-editor',
component: TextEditorComponent
}
]),
],
declarations: [DateTimePickerComponent, TypeAheadComponent, TextEditorComponent],
exports: [RouterModule]
})
export class ExtraComponentsModule { }

View File

@@ -0,0 +1,38 @@
import * as Quill from 'quill';
export interface Config {
container: string;
unit: 'word'|'char';
}
export interface QuillInstance {
on: Function;
getText: Function;
}
export default class Counter {
quill: QuillInstance;
options: Config;
constructor(quill, options) {
this.quill = quill;
this.options = options;
const container = document.querySelector(this.options.container);
this.quill.on('text-change', () => {
const length = this.calculate();
container.innerHTML = length + ' ' + this.options.unit + 's';
});
}
calculate() {
const text = this.quill.getText().trim();
if (this.options.unit === 'word') {
return !text ? 0 : text.split(/\s+/).length;
}
return text.length;
}
}

View File

@@ -0,0 +1,5 @@
:host ::ng-deep .ql-snow .ql-tooltip {
z-index:1 !important;
left: -1.7969px !important;
top: 26px !important;
}

View File

@@ -0,0 +1,76 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<div class="content-body">
<h3>Quill Editor</h3>
<p>quill editor with angular and TypeScript. ngx-quill is the new angular 2 and beyond implementation of ngQuill.
</p>
<section class="default-editor">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Default editor</h4>
</div>
<div class="card-content">
<div class="card-body">
<div class="editor">
<quill-editor [styles]="{height: '200px'}" (onFocus)="focus()" (onBlur)="blur()"
></quill-editor>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
<!-- Default Editor end -->
<section class="editor">
<div class="row">
<div class="col-12">
<div class="card">
<div class="card-header">
<h4 class="card-title">Reactive Forms and patch value</h4>
</div>
<div class="card-content">
<div class="card-body">
<div class="editor">
<button type="button" class="btn btn-primary mr-1 mb-1" (click)="hide=!(!!hide)">
Hide / Show
</button>
<button type="button" class="btn btn-primary mr-1 mb-1"
(click)="form.enabled ? form.disable() : form.enable()">
Disable / Enable
</button>
<button type="button" class="btn btn-primary mr-1 mb-1"
(click)="backgroundColor = backgroundColor ? '' : 'grey'">Toggle
BackgroundColor
</button>
<form [formGroup]="form">
{{ form.get('editor').value }}
<button type="button" class="btn btn-primary mr-1 mb-1" (click)="patchValue()">PatchValue</button>
<button type="button" class="btn btn-primary mr-1 mb-1" (click)="setControl()">SetControl</button>
<quill-editor #editor [style.display]="hide ? 'none' : 'block'"
[styles]="{ backgroundColor:backgroundColor,height: '200px' }"
[formControl]="form.controls['editor']">
</quill-editor>
</form>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TextEditorComponent } from './text-editor.component';
describe('TextEditorComponent', () => {
let component: TextEditorComponent;
let fixture: ComponentFixture<TextEditorComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ TextEditorComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TextEditorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,88 @@
import { Component, ElementRef, ViewChild, ViewEncapsulation, OnInit } from '@angular/core';
import { FormBuilder, FormControl, FormGroup } from '@angular/forms';
import { QuillEditorComponent } from 'ngx-quill';
import { debounceTime, distinctUntilChanged } from 'rxjs/operators';
@Component({
selector: 'app-text-editor',
templateUrl: './text-editor.component.html',
styleUrls: ['./text-editor.component.css']
})
export class TextEditorComponent implements OnInit {
public breadcrumb: any;
backgroundColor: any;
blured = false;
focused = false;
hide = false;
form: FormGroup;
@ViewChild('editor', { static: true }) editor: QuillEditorComponent;
constructor(fb: FormBuilder) {
this.form = fb.group({
editor: ['']
});
}
ngOnInit() {
this.form
.controls
.editor
.valueChanges.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe((data) => {
});
this.editor
.onContentChanged
.pipe(
debounceTime(400),
distinctUntilChanged()
)
.subscribe((data) => {
});
this.breadcrumb = {
'mainlabel': 'Text-Editor',
'links': [
{
'name': 'Home',
'isLink': true,
'link': '/dashboard/sales'
},
{
'name': 'Extra Components',
'isLink': true,
'link': '#'
},
{
'name': 'Text-Editor',
'isLink': false
}
]
};
}
focus() {
this.focused = true;
this.blured = false;
}
blur() {
this.focused = false;
this.blured = true;
}
setControl() {
this.form.setControl('editor', new FormControl('test - new Control'));
}
patchValue() {
this.form.get('editor').patchValue(`${this.form.get('editor').value} patched!`);
}
}

View File

@@ -0,0 +1,3 @@
:host ::ng-deep .block-ui-wrapper {
background: rgba(255, 249, 249, 0.5) !important;
}

View File

@@ -0,0 +1,89 @@
<div class="app-content content">
<div class="content-wrapper">
<div class="content-header row mb-1">
<app-breadcrumb class="col-12" [breadcrumb]="breadcrumb"></app-breadcrumb>
</div>
<!-- Typeahead js start -->
<section class="typeahead" id="typeahead">
<div class="row">
<div class="col-12" *blockUI="'typeAhead'; message: 'Loading'">
<m-card [options]="options" (reloadFunction)="reloadTypeAhead($event)">
<ng-container mCardHeaderTitle>
Typeahead
</ng-container>
<ng-container mCardBody>
<div class="row">
<div class="col-xl-6 col-lg-12">
<fieldset>
<h5>Basic Typeahead</h5>
<p class="text-muted">When initializing a <code>typeahead</code>, you pass the plugin method one
or more datasets. The source of a dataset is responsible for computing a set of suggestions for
a given query.</p>
<div class="form-group">
<input id="typeahead-basic" type="text" class="form-control" [(ngModel)]="basicModel"
[ngbTypeahead]="search" />
</div>
</fieldset>
<fieldset>
<h5>Typeahead with open on focus</h5>
<p class="text-muted">It is possible to get the focus events with the current input value to emit
results on focus with a great flexibility.</p>
<div class="form-group">
<input id="typeahead-focus" type="text" class="form-control" [(ngModel)]="openOnFocusModel"
[ngbTypeahead]="searchOnFocus" (focus)="focus$.next($event.target.value)" #instance="ngbTypeahead" />
</div>
</fieldset>
<fieldset>
<h5>Typeahea with formatted results</h5>
<p class="text-muted">A typeahead example that uses a formatter function for string results. For
example display search results in upper case.</p>
<div class="form-group">
<input id="typeahead-format" type="text" class="form-control" [(ngModel)]="formattedResultsModel"
[ngbTypeahead]="searchForFormattedResults" [resultFormatter]="formatter" />
</div>
</fieldset>
</div>
<div class="col-xl-6 col-lg-12">
<fieldset>
<h5>Typeahead with configuration</h5>
<p class="text-muted">For more advanced use cases, Typeahead with configuration gives flexibility.
This typeahead shows a hint when the input matches because the default values have been
customized.</p>
<div class="form-group">
<input id="typeahead-config" type="text" class="form-control" [(ngModel)]="typeaheadConfigModel"
[ngbTypeahead]="searchWithConfig" />
</div>
</fieldset>
<fieldset>
<h5>Typeahead with Service </h5>
<p class="text-muted">A typeahead example which gets the results from the service.</p>
<div class="form-group">
<input id="typeahead-http" type="text" class="form-control" [(ngModel)]="searviceModel"
[ngbTypeahead]="searchFromService" placeholder="Search from service" />
</div>
</fieldset>
<fieldset>
<h5>Typeahead with custom template</h5>
<p class="text-muted">A typeahead example that uses a custom template for results display, an
object as the model,
and the highlight directive to highlight the term inside the custom template.</p>
<ng-template #rt let-r="result" let-t="term">
<img [src]="'https://upload.wikimedia.org/wikipedia/commons/thumb/' + r['flag']" class="mr-1"
style="width: 16px">
<ngb-highlight [result]="r.name" [term]="t"></ngb-highlight>
</ng-template>
<div class="form-group">
<input id="typeahead-template" type="text" class="form-control"
[(ngModel)]="typeaheadTemplateModel" [ngbTypeahead]="searchWithTemplate" [resultTemplate]="rt"
[inputFormatter]="formatter1" />
</div>
</fieldset>
</div>
</div>
</ng-container>
</m-card>
</div>
</div>
</section>
</div>
</div>

View File

@@ -0,0 +1,25 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { TypeAheadComponent } from './type-ahead.component';
describe('TypeAheadComponent', () => {
let component: TypeAheadComponent;
let fixture: ComponentFixture<TypeAheadComponent>;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
declarations: [ TypeAheadComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TypeAheadComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,187 @@
import { Component, OnInit, ViewChild, Injectable } from '@angular/core';
import {HttpClient, HttpParams} from '@angular/common/http';
import {NgbTypeahead, NgbTypeaheadConfig} from '@ng-bootstrap/ng-bootstrap';
import {Observable, Subject, merge, of} from 'rxjs';
import {catchError, debounceTime, distinctUntilChanged, filter, map, tap, switchMap} from 'rxjs/operators';
import { NgBlockUI, BlockUI } from 'ng-block-ui';
declare var require: any;
const statesJson = require('../../../../assets/data/extra-components/typeahead/typeahead.json');
const states = statesJson.states;
const statesWithFlags = statesJson.statesWithFlags;
/* Typeahead with Service */
const WIKI_URL = 'https://en.wikipedia.org/w/api.php';
const PARAMS = new HttpParams({
fromObject: {
action: 'opensearch',
format: 'json',
origin: '*'
}
});
@Injectable()
export class WikipediaService {
constructor(private http: HttpClient) {}
search(term: string) {
if (term === '') {
return of([]);
}
return this.http
.get(WIKI_URL, {params: PARAMS.set('search', term)}).pipe(
map(response => response[1])
);
}
}
/* Typeahead with Service */
@Component({
selector: 'app-type-ahead',
templateUrl: './type-ahead.component.html',
providers: [WikipediaService, NgbTypeaheadConfig],
styleUrls: ['./type-ahead.component.css']
})
export class TypeAheadComponent implements OnInit {
@BlockUI('typeAhead') blockUITypeAhead: NgBlockUI;
options = {
close: true,
expand: true,
minimize: true,
reload: true
};
public breadcrumb: any;
constructor(private _service: WikipediaService,
config: NgbTypeaheadConfig) {
config.showHint = true;
}
/* Basic Typeahed : START */
public basicModel: any;
/* Basic Typeahed : END */
/* Open on Focus : START */
public openOnFocusModel: any;
@ViewChild('instance', { static: true }) instance: NgbTypeahead;
focus$ = new Subject<string>();
click$ = new Subject<string>();
/* Open on Focus : END */
/* Formatted Results : START */
public formattedResultsModel: any;
/* Formatted Resutls : END */
/* Typeahead with Service */
public searviceModel: any;
searching = false;
searchFailed = false;
/* Typehead with service */
/* Typeahead with template */
public typeaheadTemplateModel: any;
/* Typeahead with template */
/* Typeahead with Config */
public typeaheadConfigModel: any;
popupOpen: Observable<boolean>;
ngOnInit() {
this.breadcrumb = {
'mainlabel': 'TypeAhead',
'links': [
{
'name': 'Home',
'isLink': true,
'link': '/dashboard/sales'
},
{
'name': 'Extra Components',
'isLink': true,
'link': '#'
},
{
'name': 'TypeAhead',
'isLink': false
}
]
};
}
search = (text$: Observable<string>) =>
text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term => term.length < 1 ? []
: states.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10))
)
searchOnFocus = (text$: Observable<string>) => {
const debouncedText$ = text$.pipe(debounceTime(200), distinctUntilChanged());
const inputFocus$ = this.focus$;
return merge(debouncedText$, inputFocus$).pipe(
map(term => (term === '' ? states
: states.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1)).slice(0, 10))
);
}
reloadTypeAhead() {
this.blockUITypeAhead.start('Loading..');
setTimeout(() => {
this.blockUITypeAhead.stop();
}, 2500);
}
formatter = (result: string) => result.toUpperCase();
searchForFormattedResults = (text$: Observable<string>) =>
text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term => term === '' ? []
: states.filter(v => v.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10))
)
searchFromService = (text$: Observable<string>) =>
text$.pipe(
debounceTime(300),
distinctUntilChanged(),
tap(() => this.searching = true),
switchMap(term =>
this._service.search(term).pipe(
tap(() => this.searchFailed = false),
catchError(() => {
this.searchFailed = true;
return of([]);
}))
),
tap(() => this.searching = false)
)
formatter1 = (x: {name: string}) => x.name;
searchWithTemplate = (text$: Observable<string>) =>
text$.pipe(
debounceTime(200),
map(term => term === '' ? []
: statesWithFlags.filter(v => v.name.toLowerCase().indexOf(term.toLowerCase()) > -1).slice(0, 10))
)
searchWithConfig = (text$: Observable<string>) =>
text$.pipe(
debounceTime(200),
distinctUntilChanged(),
map(term => term.length < 1 ? []
: states.filter(v => v.toLowerCase().startsWith(term.toLocaleLowerCase())).splice(0, 10))
)
/* Typeahead with Config */
}