Skip to content
This repository has been archived by the owner on Sep 23, 2022. It is now read-only.

Commit

Permalink
feat(cl-image): Better management of changes on component input
Browse files Browse the repository at this point in the history
All changes on input are propagated to the imageUrl
Support `format` input
Add new image service to retrieve the cloudinary image urls
  • Loading branch information
jboulay committed Oct 13, 2016
1 parent 1609381 commit 41bf4be
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 53 deletions.
12 changes: 6 additions & 6 deletions demo/demo.component.html
Expand Up @@ -21,7 +21,7 @@ <h1 class="page-header">Cloudinary image directive</h1>
</code>
</pre>
<p style="text-align:center;">
<cl-image public-id="sample" [options]="options" height="334"></cl-image>
<cl-image public-id="sample" [options]="options" format="jpg" height="334"></cl-image>
</p>
<p>Displaying the same image with a limited <code>height</code> of 200 pixels</p>
<pre>
Expand All @@ -30,7 +30,7 @@ <h1 class="page-header">Cloudinary image directive</h1>
</code>
</pre>
<p style="text-align:center;">
<cl-image public-id="sample" [options]="options" height="200"></cl-image>
<cl-image public-id="sample" [options]="options" format="jpg" height="200"></cl-image>
</p>
<div>Image transformations are limited to the following parameters in the current version:
<ul>
Expand All @@ -50,7 +50,7 @@ <h1 class="page-header">Cloudinary image directive</h1>
</code>
</pre>
<p style="text-align:center;">
<cl-image public-id="sample" [options]="options" width="300" height="200" crop="crop"></cl-image>
<cl-image public-id="sample" [options]="options" format="jpg" width="300" height="200" crop="crop"></cl-image>
</p>
<p>Another example, displaying an image with automatic cropping and fill mode.</p>
<pre>
Expand All @@ -60,15 +60,15 @@ <h1 class="page-header">Cloudinary image directive</h1>
</pre>
<p style="text-align:center;">
<span style="display:inline-block;vertical-align:top;margin-left:10px;margin-right:10px">
<cl-image public-id="basketball_in_net" [options]="options" height="200"></cl-image>
<cl-image public-id="basketball_in_net" [options]="options" format="jpg" height="200"></cl-image>
<p><b>Original</b></p>
</span>
<span style="display:inline-block;vertical-align:top;margin-left:10px;margin-right:10px">
<cl-image public-id="basketball_in_net" [options]="options" width="200" height="300" crop="fill" gravity="center"></cl-image>
<cl-image public-id="basketball_in_net" [options]="options" format="jpg" width="200" height="300" crop="fill" gravity="center"></cl-image>
<p><b>Regular fill</b></p>
</span>
<span style="display:inline-block;vertical-align:top;margin-left:10px;margin-right:10px">
<cl-image public-id="basketball_in_net" [options]="options" width="200" height="300" crop="fill" gravity="auto"></cl-image>
<cl-image public-id="basketball_in_net" [options]="options" format="jpg" width="200" height="300" crop="fill" gravity="auto"></cl-image>
<p><b>Automatic fill</b></p>
</span>
</p>
Expand Down
88 changes: 42 additions & 46 deletions src/cloudinary-image.component.ts
@@ -1,71 +1,67 @@
import { Component, Input, OnInit } from '@angular/core';
import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core';
import { CloudinaryOptions } from './cloudinary-options.class';
import { CloudinaryTransforms } from './cloudinary-transforms.class';
import { CloudinaryImageService } from './cloudinary-image.service';

@Component({
selector: 'cl-image',
template: `
<img [src]="imageUrl" [style.height.px]="height" [style.width.px]="width">
<img [src]="imageUrl">
`
})
export class CloudinaryImageComponent implements OnInit {
export class CloudinaryImageComponent implements OnInit, OnChanges {
imageUrl: string = '';
transforms: CloudinaryTransforms = new CloudinaryTransforms();

@Input('public-id') publicId: string;
@Input() options: CloudinaryOptions;
@Input() height: string;
@Input() width: string;
@Input() crop: string;
@Input() gravity: string;
@Input() x: string;
@Input() y: string;

constructor(private _imageService: CloudinaryImageService) { }

ngOnInit(): void {
if (!this.options) throw new Error('CloudinaryOptions are required for cl-image component');
}

@Input('public-id')
set publicId(value: string) {
this.imageUrl = this.getImageUrl(value);
}

private getImageUrl(publicId: string): string {
let resourceUrl: string = '';

if (publicId) {
resourceUrl = 'https://res.cloudinary.com/' +
this.options.cloud_name + '/' +
'image/upload/' +
this.getTransformationForUrlSegment() +
publicId + '.jpg';
ngOnChanges(changes: SimpleChanges): void {
if (this.publicId && this.options) {
this.imageUrl = this._imageService.getImageUrl(this.publicId, this.options, this.transforms);
}else {
this.imageUrl = '';
}
return resourceUrl;
}

private getTransformationForUrlSegment(): string {
let transformSegment: string = '';
@Input()
set format(value: string){
this.transforms.format = value;
}

transformSegment += this.toPropertySegment(transformSegment, 'height', this.height);
transformSegment += this.toPropertySegment(transformSegment, 'width', this.width);
transformSegment += this.toPropertySegment(transformSegment, 'gravity', this.gravity);
transformSegment += this.toPropertySegment(transformSegment, 'crop', this.crop);
transformSegment += this.toPropertySegment(transformSegment, 'x', this.x);
transformSegment += this.toPropertySegment(transformSegment, 'y', this.y);
@Input()
set height(value: string) {
this.transforms.height = value;
}

if (transformSegment.length > 0) {
transformSegment += '/';
}
@Input()
set width(value: string) {
this.transforms.width = value;
}

return transformSegment;
@Input()
set crop(value: string) {
this.transforms.crop = value;
}

private toPropertySegment(segment: string, name: string, value: any): string {
let newSegment: string = '';
@Input()
set gravity(value: string) {
this.transforms.gravity = value;
}

if (name && value) {
if (segment.length > 0) {
newSegment += ',';
}
@Input()
set x(value: string) {
this.transforms.x = value;
}

newSegment += name.substring(0, 1).toLowerCase() + '_' + value;
}
return newSegment;
@Input()
set y(value: string) {
this.transforms.y = value;
}
}
}
49 changes: 49 additions & 0 deletions src/cloudinary-image.service.ts
@@ -0,0 +1,49 @@
import { Injectable } from '@angular/core';
import { CloudinaryOptions } from './cloudinary-options.class.ts';
import { CloudinaryTransforms } from './cloudinary-transforms.class.ts';

const CLOUDINARY_URL: string = 'https://res.cloudinary.com/';

@Injectable()
export class CloudinaryImageService {

getImageUrl(publicId: string, options: CloudinaryOptions, transforms: CloudinaryTransforms): string {
return CLOUDINARY_URL +
options.cloud_name + '/' +
'image/upload/' +
getTransformationForUrlSegment(transforms) +
publicId + '.' + (transforms.format || 'jpg');

}

}

function getTransformationForUrlSegment(transforms: CloudinaryTransforms): string {
let transformSegment: string = '';

transformSegment += toPropertySegment(transformSegment, 'height', transforms.height);
transformSegment += toPropertySegment(transformSegment, 'width', transforms.width);
transformSegment += toPropertySegment(transformSegment, 'gravity', transforms.gravity);
transformSegment += toPropertySegment(transformSegment, 'crop', transforms.crop);
transformSegment += toPropertySegment(transformSegment, 'x', transforms.x);
transformSegment += toPropertySegment(transformSegment, 'y', transforms.y);

if (transformSegment.length > 0) {
transformSegment += '/';
}

return transformSegment;
}

function toPropertySegment(segment: string, name: string, value: any): string {
let newSegment: string = '';

if (name && value) {
if (segment.length > 0) {
newSegment += ',';
}

newSegment += name.substring(0, 1).toLowerCase() + '_' + value;
}
return newSegment;
}
10 changes: 10 additions & 0 deletions src/cloudinary-transforms.class.ts
@@ -0,0 +1,10 @@
export class CloudinaryTransforms {
format: string;
height: string;
width: string;
crop: string;
gravity: string;
x: string;
y: string;

}
5 changes: 5 additions & 0 deletions src/cloudinary.module.ts
Expand Up @@ -2,9 +2,11 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {FileDropDirective, FileSelectDirective} from 'ng2-file-upload';
import {CloudinaryImageComponent} from './cloudinary-image.component';
import {CloudinaryImageService} from './cloudinary-image.service';

export {CloudinaryOptions} from './cloudinary-options.class';
export {CloudinaryUploader} from './cloudinary-uploader.service';
export {CloudinaryImageService};

@NgModule({
declarations: [
Expand All @@ -17,6 +19,9 @@ export {CloudinaryUploader} from './cloudinary-uploader.service';
CloudinaryImageComponent,
FileDropDirective,
FileSelectDirective
],
providers: [
CloudinaryImageService
]
})
export class Ng2CloudinaryModule {}
4 changes: 3 additions & 1 deletion test/cloudinary-image.component.spec.ts
Expand Up @@ -51,6 +51,7 @@ describe('CloudinaryImage component', () => {
cloud_name: 'ekito'
});
clImageComponent.publicId = 'testPublicId';
clImageComponent.ngOnChanges(null);
fixture.detectChanges();

let expectedImageUrl: string = 'https://res.cloudinary.com/ekito/image/upload/testPublicId.jpg';
Expand All @@ -68,11 +69,12 @@ describe('CloudinaryImage component', () => {
clImageComponent.height = '100';
clImageComponent.width = '150';
clImageComponent.publicId = 'testPublicId';
clImageComponent.ngOnChanges(null);
fixture.detectChanges();

let expectedImageUrl: string = 'https://res.cloudinary.com/ekito/image/upload/h_100,w_150/testPublicId.jpg';
expect(clImageComponent.imageUrl).to.equal(expectedImageUrl);
expect(fixture.nativeElement.innerHTML.trim())
.to.equal('<img ng-reflect-src="' + expectedImageUrl + '" src="' + expectedImageUrl + '" style="height: 100px; width: 150px;">');
.to.equal('<img ng-reflect-src="' + expectedImageUrl + '" src="' + expectedImageUrl + '">');
});
});

0 comments on commit 41bf4be

Please sign in to comment.