From 134fab70702ff06bf45abf4dd43b971306f459dc Mon Sep 17 00:00:00 2001 From: Ricardo Marques Date: Tue, 27 Feb 2018 09:51:54 +0000 Subject: [PATCH] mgr/dashboard: Add DimlessBinaryDirective Signed-off-by: Ricardo Marques --- .../dimless-binary.directive.spec.ts | 12 ++ .../directives/dimless-binary.directive.ts | 117 ++++++++++++++++++ .../frontend/src/app/shared/shared.module.ts | 5 +- 3 files changed, 133 insertions(+), 1 deletion(-) create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.spec.ts create mode 100644 src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.ts diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.spec.ts new file mode 100644 index 0000000000000..5822e7d97d578 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.spec.ts @@ -0,0 +1,12 @@ +import { DimlessBinaryDirective } from './dimless-binary.directive'; + +export class MockElementRef { + nativeElement: {}; +} + +describe('DimlessBinaryDirective', () => { + it('should create an instance', () => { + const directive = new DimlessBinaryDirective(new MockElementRef(), null, null, null); + expect(directive).toBeTruthy(); + }); +}); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.ts new file mode 100644 index 0000000000000..f30c80f1f06e2 --- /dev/null +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/directives/dimless-binary.directive.ts @@ -0,0 +1,117 @@ +import { + Directive, + ElementRef, + EventEmitter, + HostListener, + Input, + OnInit, + Output +} from '@angular/core'; +import { NgControl } from '@angular/forms'; + +import * as _ from 'lodash'; + +import { DimlessBinaryPipe } from '../pipes/dimless-binary.pipe'; +import { FormatterService } from '../services/formatter.service'; + +@Directive({ + selector: '[cdDimlessBinary]' +}) +export class DimlessBinaryDirective implements OnInit { + + @Output() ngModelChange: EventEmitter = new EventEmitter(); + + /** + * Minimum size in bytes. + * If user enter a value lower than , + * the model will automatically be update to . + * + * If is used, this value should be a power of . + * + * Example: + * Given minBytes=4096 (4KiB), if user type 1KiB, then model will be updated to 4KiB + */ + @Input() minBytes: number; + + /** + * Maximum size in bytes. + * If user enter a value greater than , + * the model will automatically be update to . + * + * If is used, this value should be a power of . + * + * Example: + * Given maxBytes=3145728 (3MiB), if user type 4MiB, then model will be updated to 3MiB + */ + @Input() maxBytes: number; + + /** + * Value will be rounded up the nearest power of + * + * Example: + * Given roundPower=2, if user type 7KiB, then model will be updated to 8KiB + * Given roundPower=2, if user type 5KiB, then model will be updated to 4KiB + */ + @Input() roundPower: number; + + /** + * Default unit that should be used when user do not type a unit. + * By default, "MiB" will be used. + * + * Example: + * Given defaultUnit=null, if user type 7, then model will be updated to 7MiB + * Given defaultUnit=k, if user type 7, then model will be updated to 7KiB + */ + @Input() defaultUnit: string; + + private el: HTMLInputElement; + + constructor(private elementRef: ElementRef, + private control: NgControl, + private dimlessBinaryPipe: DimlessBinaryPipe, + private formatter: FormatterService) { + this.el = this.elementRef.nativeElement; + } + + ngOnInit() { + this.setValue(this.el.value); + } + + setValue(value) { + if (/^[\d.]+$/.test(value)) { + value += this.defaultUnit || 'm'; + } + const size = this.formatter.toBytes(value); + const roundedSize = this.round(size); + this.el.value = this.dimlessBinaryPipe.transform(roundedSize); + if (size !== null) { + this.ngModelChange.emit(this.el.value); + this.control.control.setValue(this.el.value); + } else { + this.ngModelChange.emit(null); + this.control.control.setValue(null); + } + } + + round(size) { + if (size !== null && size !== 0) { + if (!_.isUndefined(this.minBytes) && size < this.minBytes) { + return this.minBytes; + } + if (!_.isUndefined(this.maxBytes) && size > this.maxBytes) { + return this.maxBytes; + } + if (!_.isUndefined(this.roundPower)) { + const power = Math.round(Math.log(size) / Math.log(this.roundPower)); + return Math.pow(this.roundPower, power); + } + } + return size; + } + + @HostListener('blur', ['$event.target.value']) + onBlur(value) { + this.setValue(value); + } + +} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/shared.module.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/shared.module.ts index 7651338d9c0bc..96c6facd2d9de 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/shared.module.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/shared.module.ts @@ -3,6 +3,7 @@ import { NgModule } from '@angular/core'; import { ComponentsModule } from './components/components.module'; import { DataTableModule } from './datatable/datatable.module'; +import { DimlessBinaryDirective } from './directives/dimless-binary.directive'; import { PasswordButtonDirective } from './directives/password-button.directive'; import { PipesModule } from './pipes/pipes.module'; import { AuthGuardService } from './services/auth-guard.service'; @@ -22,13 +23,15 @@ import { ServicesModule } from './services/services.module'; DataTableModule ], declarations: [ - PasswordButtonDirective + PasswordButtonDirective, + DimlessBinaryDirective ], exports: [ ComponentsModule, PipesModule, ServicesModule, PasswordButtonDirective, + DimlessBinaryDirective, DataTableModule ], providers: [ -- 2.39.5