Skip to content

Commit

Permalink
feat: created image-input
Browse files Browse the repository at this point in the history
  • Loading branch information
alisahinozcelik committed May 16, 2020
1 parent b29fa3b commit f0f8907
Show file tree
Hide file tree
Showing 18 changed files with 275 additions and 58 deletions.
29 changes: 29 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: Npm Package

on:
release:
types: [created]

jobs:
publish-npm:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set env
run: echo ::set-env name=PACKAGE_VERSION::$(echo ${GITHUB_REF:10})
- uses: actions/setup-node@v1
with:
node-version: 12
registry-url: https://registry.npmjs.org/
- run: npm install
# - run: npm test
- run: npm run version-update
- run: npm run build
# - run: npm run change-ts-version
# - run: rm -rf node_modules
# - run: rm ./package-lock.json
# - run: npm install
# - run: npm run prepare:legacy
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
24 changes: 1 addition & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,5 @@
# NgUtils

This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.0.6.
A package to store commonly used angular application contents

## Development server

Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files.

## Code scaffolding

Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`.

## Build

Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build.

## Running unit tests

Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io).

## Running end-to-end tests

Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/).

## Further help

To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md).
12 changes: 9 additions & 3 deletions angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,12 @@
"projectType": "library",
"root": "projects/ng-utils",
"sourceRoot": "projects/ng-utils/src",
"prefix": "lib",
"prefix": "tha",
"schematics": {
"@schematics/angular:component": {
"style": "scss"
}
},
"architect": {
"build": {
"builder": "@angular-devkit/build-ng-packagr:build",
Expand Down Expand Up @@ -97,7 +102,8 @@
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
"options": {
"browserTarget": "playground:build"
"browserTarget": "playground:build",
"port": 3600
},
"configurations": {
"production": {
Expand Down Expand Up @@ -156,4 +162,4 @@
}
}},
"defaultProject": "ng-utils"
}
}
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 11 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
{
"name": "ng-utils",
"name": "@thalesrc/ng-utils",
"version": "0.0.0",
"description": "A package to store commonly used angular application contents",
"keywords": ["angular", "ng", "util", "utils", "library", "image-input"],
"author": {
"name": "Ali Şahin Özçelik",
"email": "alisahinozcelik@gmail.com"
},
"scripts": {
"start": "ng serve playground",
"build": "ng build ng-utils --prod",
"version-update": "npm version $PACKAGE_VERSION --no-git-tag-version",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e"
},
"license": "MIT",
"private": false,
"publishConfig": {
"access": "public"
},
"dependencies": {
"@angular/animations": "~8.0.3",
"@angular/common": "~8.0.3",
Expand All @@ -22,19 +29,20 @@
"@angular/platform-browser": "~8.0.3",
"@angular/platform-browser-dynamic": "~8.0.3",
"@angular/router": "~8.0.3",
"@thalesrc/js-utils": "^2.0.8",
"rxjs": "~6.4.0",
"tslib": "^1.9.0",
"zone.js": "~0.9.1"
},
"devDependencies": {
"@angular-devkit/build-angular": "~0.800.6",
"@angular-devkit/build-angular": "^0.800.6",
"@angular-devkit/build-ng-packagr": "~0.800.6",
"@angular/cli": "~8.0.6",
"@angular/compiler-cli": "~8.0.3",
"@angular/language-service": "~8.0.3",
"@types/node": "~8.9.4",
"@types/jasmine": "~3.3.8",
"@types/jasminewd2": "~2.0.3",
"@types/node": "~8.9.4",
"codelyzer": "^5.0.0",
"jasmine-core": "~3.4.0",
"jasmine-spec-reporter": "~4.2.1",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ImageInputDirective } from './image-input.directive';

describe('ImageInputDirective', () => {
it('should create an instance', () => {
const directive = new ImageInputDirective();
expect(directive).toBeTruthy();
});
});
133 changes: 133 additions & 0 deletions projects/ng-utils/src/lib/form/image-input/image-input.directive.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { Directive, forwardRef, Input, OnInit, ElementRef, HostListener } from '@angular/core';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR, ControlValueAccessor, Validator } from '@angular/forms';
import { noop } from '@thalesrc/js-utils/function/noop';
import { BehaviorSubject, combineLatest, fromEvent, merge } from 'rxjs';
import { map, distinctUntilChanged, first } from 'rxjs/operators';
import { Unsubscriber } from 'projects/ng-utils/src/utils/unsubscriber';
import { shareLast } from 'projects/ng-utils/src/utils/share-last';

@Directive({
// tslint:disable-next-line:directive-selector
selector: 'img[thaImageInput]',
providers: [
{ provide: NG_VALIDATORS, useExisting: ImageInputDirective, multi: true },
{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ImageInputDirective), multi: true}
],
exportAs: 'thaImageInput'
})
export class ImageInputDirective extends Unsubscriber implements ControlValueAccessor, Validator, OnInit {
// tslint:disable-next-line:max-line-length
private static TRANSPARENT_URL = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8Wg8AAm8BdpLdi+IAAAAASUVORK5CYII=';

private onChange: (value: File) => void = noop;
private onTouched: () => void = noop;
private onValidatorChange: () => void = noop;

private input = ImageInputDirective.createInput();

private src$ = new BehaviorSubject<string>(ImageInputDirective.TRANSPARENT_URL);
private modelFile$ = new BehaviorSubject<File>(null);

private emptySource$ = this.src$.pipe(
distinctUntilChanged()
);

private inputChange$ = fromEvent(this.input, 'change').pipe(
map(event => {
let file = this.input.files[0] || null;

if (file && !['image/jpeg', 'image/png', 'image/gif'].some(type => type === file.type)) {
this.input.value = '';
file = null;
}

return file;
})
);

public file$ = merge(this.modelFile$, this.inputChange$).pipe(shareLast());

@Input()
private disabled = false;

@Input('src')
private set _src(src: string) {
console.log(src);

this.src$.next(src);
}

private static createInput() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.jpg,.jpeg,.png,.gif';

return input;
}

constructor(
private el: ElementRef<HTMLImageElement>
) {
super();
}

@HostListener('click')
public onHostClick() {
if (this.disabled) {
return;
}

this.onTouched();
this.input.click();
}

public ngOnInit() {
this.subs = this.inputChange$.subscribe(value => {
this.onChange(value);
});

this.subs = combineLatest(this.file$, this.emptySource$).subscribe(([file, src]) => {
if (!file) {
this.el.nativeElement.src = src;

return;
}

this.el.nativeElement.src = URL.createObjectURL(file);
});
}

public registerOnChange(fn: (value: File) => void): void {
this.onChange = fn;
}

public registerOnTouched(fn: () => void): void {
this.onTouched = fn;
}

public async writeValue(value: File) {
if (!value) {
value = null;
}

const current = await this.file$.pipe(first()).toPromise();

if (value === current) {
return;
}

this.modelFile$.next(value);
}

public setDisabledState(disabled: boolean): void {
this.disabled = disabled;
}

public registerOnValidatorChange(fn: () => void): void {
this.onValidatorChange = fn;
}

public validate() {
return null;
}
}
18 changes: 18 additions & 0 deletions projects/ng-utils/src/lib/form/image-input/image-input.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { CommonModule } from '@angular/common';
import { ImageInputDirective } from './image-input.directive';

@NgModule({
declarations: [
ImageInputDirective
],
imports: [
CommonModule,
FormsModule,
],
exports: [
ImageInputDirective
]
})
export class ImageInputModule { }
2 changes: 2 additions & 0 deletions projects/ng-utils/src/lib/form/image-input/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from './image-input.module';
export * from './image-input.directive';
8 changes: 5 additions & 3 deletions projects/ng-utils/src/public-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
* Public API Surface of ng-utils
*/

export * from './lib/ng-utils.service';
export * from './lib/ng-utils.component';
export * from './lib/ng-utils.module';
// export * from './lib/ng-utils.service';
// export * from './lib/ng-utils.component';
// export * from './lib/ng-utils.module';
export * from './lib/form/image-input';
export * from './utils/unsubscriber';
6 changes: 6 additions & 0 deletions projects/ng-utils/src/utils/share-last.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { MonoTypeOperatorFunction } from 'rxjs';
import { shareReplay } from 'rxjs/operators';

export function shareLast<T>(): MonoTypeOperatorFunction<T> {
return shareReplay({refCount: false, bufferSize: 1});
}
21 changes: 21 additions & 0 deletions projects/ng-utils/src/utils/unsubscriber.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { OnDestroy } from '@angular/core';
import { Observable, Subject, Subscription } from 'rxjs';

const SUBS = Symbol('Subscriptions');

export abstract class Unsubscriber implements OnDestroy {
private [SUBS] = new Subscription();

protected onDestroy$: Observable<void> = new Subject();

protected set subs(subscription: Subscription) {
this[SUBS].add(subscription);
}

public ngOnDestroy() {
(this.onDestroy$ as Subject<void>).next();
(this.onDestroy$ as Subject<void>).complete();

this[SUBS].unsubscribe();
}
}
23 changes: 4 additions & 19 deletions projects/playground/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -1,20 +1,5 @@
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
<h1>
Welcome to {{ title }}!
</h1>
<img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Here are some links to help you start: </h2>
<ul>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/tutorial">Tour of Heroes</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://angular.io/cli">CLI Documentation</a></h2>
</li>
<li>
<h2><a target="_blank" rel="noopener" href="https://blog.angular.io/">Angular blog</a></h2>
</li>
</ul>
<form #form="ngForm">
<img [src]="image | async" thaImageInput [disabled]="false" ngModel name="image">
</form>

<pre>{{form.value | json}}</pre>
4 changes: 4 additions & 0 deletions projects/playground/src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
img {
width: 300px;
height: auto;
}

0 comments on commit f0f8907

Please sign in to comment.