Skip to content

Commit

Permalink
feat: option to upload images
Browse files Browse the repository at this point in the history
closes #34
  • Loading branch information
sibiraj-s committed Feb 19, 2018
1 parent 49c64cd commit 09b69b5
Show file tree
Hide file tree
Showing 14 changed files with 1,331 additions and 3,226 deletions.
4,169 changes: 1,040 additions & 3,129 deletions package-lock.json

Large diffs are not rendered by default.

5 changes: 2 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
},
"devDependencies": {
"@angular/animations": "^5.2.0",
"@angular/cli": "1.6.8",
"@angular/cli": "1.7.0",
"@angular/common": "^5.2.0",
"@angular/compiler": "^5.2.0",
"@angular/compiler-cli": "^5.2.0",
Expand All @@ -57,7 +57,7 @@
"@angular/platform-browser": "^5.2.0",
"@angular/platform-browser-dynamic": "^5.2.0",
"@angular/router": "^5.2.0",
"@compodoc/compodoc": "^1.0.6",
"@compodoc/compodoc": "^1.0.7",
"@types/jasmine": "~2.8.3",
"@types/jasminewd2": "~2.0.2",
"@types/node": "~6.0.60",
Expand All @@ -82,7 +82,6 @@
"protractor": "~5.1.2",
"rxjs": "^5.5.6",
"ts-node": "~4.1.0",
"tsickle": "^0.26.0",
"tslint": "~5.9.1",
"typescript": "~2.5.3",
"zone.js": "^0.8.19"
Expand Down
1 change: 1 addition & 0 deletions scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ rm -rf dist/

# delete unwanted folders
rm -rf .ng_build
rm -rf .ng_pkg_build
1 change: 1 addition & 0 deletions src/app/ngx-editor/common/ngx-editor.defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export const ngxEditorConfig = {
enableToolbar: true,
showToolbar: true,
placeholder: 'Enter text here...',
imageEndPoint: '',
toolbar: [
['bold', 'italic', 'underline', 'strikeThrough', 'superscript', 'subscript'],
['justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'indent', 'outdent'],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { TestBed, inject } from '@angular/core/testing';
import { HttpClientModule } from '@angular/common/http';

import { CommandExecutorService } from './command-executor.service';
import { MessageService } from './message.service';

describe('CommandExecutorService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [CommandExecutorService]
imports: [HttpClientModule],
providers: [CommandExecutorService, MessageService]
});
});

Expand Down
75 changes: 39 additions & 36 deletions src/app/ngx-editor/common/services/command-executor.service.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import { Injectable } from '@angular/core';
import { HttpClient, HttpRequest } from '@angular/common/http';
import { MessageService } from './message.service';
import * as Utils from '../utils/ngx-editor.utils';
import { map, tap, last, catchError } from 'rxjs/operators';

@Injectable()
export class CommandExecutorService {

savedSelection: any = undefined;

constructor(private _http: HttpClient, private _messageService: MessageService) { }

/**
* executes command from the toolbar
*
Expand All @@ -28,50 +33,48 @@ export class CommandExecutorService {
return;
}

// if (command === 'link') {
// this.createLink();
// return;
// }

if (command === 'image') {
this.insertImage();
return;
}

document.execCommand(command, false, null);
}

private insertImage(): void {
const imageURI = prompt('Enter Image URL', 'http://');
if (imageURI) {
const inserted = document.execCommand('insertImage', false, imageURI);
if (!inserted) {
throw new Error('Invalid URL');
insertImage(imageURI: string): void {
if (this.savedSelection) {
if (imageURI) {
const restored = Utils.restoreSelection(this.savedSelection);
if (restored) {
const inserted = document.execCommand('insertImage', false, imageURI);
if (!inserted) {
throw new Error('Invalid URL');
}
}
}
} else {
throw new Error('Range out of the editor');
}
return;
}

// private createLink(): void {
// const selection = document.getSelection();

// if (selection.anchorNode.parentElement.tagName === 'A') {
// const linkURL = prompt('Enter URL', selection.anchorNode.parentElement.getAttribute('href'));
// if (linkURL) {
// document.execCommand('createLink', false, linkURL);
// }
// } else {
// if (selection['type'] === 'None') {
// throw new Error('No selection made');
// } else {
// const linkURL = prompt('Enter URL', 'http://');
// if (linkURL) {
// document.execCommand('createLink', false, linkURL);
// }
// }
// }
// return;
// }
uploadImage(file: File, endPoint: string): any {

if (!endPoint) {
throw new Error('Image Endpoint isn`t provided or invalid');
}

const formData: FormData = new FormData();

if (file) {

formData.append('file', file);

const req = new HttpRequest('POST', endPoint, formData, {
reportProgress: true
});

return this._http.request(req);

} else {
throw new Error('Invalid Image');
}
}

createLink(params: any): void {

Expand Down
2 changes: 1 addition & 1 deletion src/app/ngx-editor/common/services/message.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Subject } from 'rxjs/Subject';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';

const FIVE_SECONDS = 5000;
const FIVE_SECONDS = 7000;

@Injectable()
export class MessageService {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,16 @@
</button>
</div>
<div class="ngx-toolbar-set">
<button type="button" class="ngx-editor-button" *ngIf="canEnableToolbarOptions('link')" (click)="buildUrlForm()" popoverTitle="Insert Link"
[popover]="insertLinkTemplate" title="Insert/Edit Link" #urlPopover="bs-popover" [disabled]="!config['enableToolbar']">
<button type="button" class="ngx-editor-button" *ngIf="canEnableToolbarOptions('link')" (click)="buildUrlForm()" [popover]="insertLinkTemplate"
title="Insert Link" #urlPopover="bs-popover" [disabled]="!config['enableToolbar']">
<i class="fa fa-link" aria-hidden="true"></i>
</button>
<button type="button" class="ngx-editor-button" *ngIf="canEnableToolbarOptions('unlink')" (click)="triggerCommand('unlink')"
title="Unlink" [disabled]="!config['enableToolbar']">
<i class="fa fa-chain-broken" aria-hidden="true"></i>
</button>
<button type="button" class="ngx-editor-button" *ngIf="canEnableToolbarOptions('image')" (click)="triggerCommand('image')"
title="Insert Image" [disabled]="!config['enableToolbar']">
<button type="button" class="ngx-editor-button" *ngIf="canEnableToolbarOptions('image')" (click)="buildInsertImageForm()"
title="Insert Image" [popover]="insertImageTemplate" #imagePopover="bs-popover" [disabled]="!config['enableToolbar']">
<i class="fa fa-picture-o" aria-hidden="true"></i>
</button>
</div>
Expand All @@ -125,22 +125,67 @@
</div>
</div>

<!-- Popover templates -->
<!-- URL Popover template -->
<ng-template #insertLinkTemplate>
<form class="ngxe-popover-form" [formGroup]="urlForm" (ngSubmit)="urlForm.valid && insertLink()" autocomplete="off">
<div class="form-group">
<label for="urlInput" class="small">URL</label>
<input type="text" class="form-control-sm" id="URLInput" aria-describedby="emailHelp" placeholder="URL" formControlName="urlLink"
required>
</div>
<div class="form-group">
<label for="urlTextInput" class="small">Text</label>
<input type="text" class="form-control-sm" id="urlTextInput" placeholder="Text" formControlName="urlText" required>
<div class="ngxe-popover-form extra-gt">
<form [formGroup]="urlForm" (ngSubmit)="urlForm.valid && insertLink()" autocomplete="off">
<div class="form-group">
<label for="urlInput" class="small">URL</label>
<input type="text" class="form-control-sm" id="URLInput" placeholder="URL" formControlName="urlLink" required>
</div>
<div class="form-group">
<label for="urlTextInput" class="small">Text</label>
<input type="text" class="form-control-sm" id="urlTextInput" placeholder="Text" formControlName="urlText" required>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="urlNewTab" formControlName="urlNewTab">
<label class="form-check-label" for="urlNewTab">Open in new tab</label>
</div>
<button type="submit" class="btn-primary btn-sm btn">Submit</button>
</form>
</div>
</ng-template>

<!-- Image Uploader Popover template -->
<ng-template #insertImageTemplate>
<div class="ngxe-popover-form image-ctnr">
<div class="imgc-topbar">
<button type="button" class="btn" (click)="isImageUploader = true">
<i class="fa fa-upload"></i>
</button>
<button type="button" class="btn" (click)="isImageUploader = false">
<i class="fa fa-link"></i>
</button>
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="urlNewTab" formControlName="urlNewTab">
<label class="form-check-label" for="urlNewTab">Open in new tab</label>
<div class="imgc-ctnt">
<div *ngIf="isImageUploader; else insertImageLink"> </div>
<div *ngIf="!isImageUploader; else imageUploder"> </div>
<ng-template #imageUploder>
<div class="ngx-insert-img-ph">
<p *ngIf="uploadComplete">Choose Image</p>
<p *ngIf="!uploadComplete">
<span>Uploading Image</span>
<br>
<span>{{ updloadPercentage }} %</span>
</p>
<div class="ngxe-img-upl-frm">
<input type="file" (change)="onFileChange($event)" accept="image/*" [disabled]="isUploading" [style.cursor]="isUploading ? 'not-allowed': 'allowed'">
</div>
</div>
</ng-template>
<ng-template #insertImageLink>
<form class="extra-gt" [formGroup]="imageForm" (ngSubmit)="imageForm.valid && insertImage()" autocomplete="off">
<div class="form-group">
<label for="imageURLInput" class="small">URL</label>
<input type="text" class="form-control-sm" id="imageURLInput" placeholder="URL" formControlName="imageUrl" required>
</div>
<button type="submit" class="btn-primary btn-sm btn">Submit</button>
</form>
</ng-template>
<div class="progress" *ngIf="!uploadComplete">
<div class="progress-bar progress-bar-striped progress-bar-animated bg-success" [ngClass]="{'bg-danger': updloadPercentage<20, 'bg-warning': updloadPercentage<50, 'bg-success': updloadPercentage>=100}"
[style.width.%]="updloadPercentage"></div>
</div>
</div>
<button type="submit" class="btn-primary btn-sm btn">Submit</button>
</form>
</div>
</ng-template>
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,18 @@
}
}

::ng-deep .popover {
border-top-right-radius: 0;
border-top-left-radius: 0;
}

::ng-deep .ngxe-popover-form {
min-width: 15rem;

&.extra-gt, .extra-gt {
padding-top: 0.5rem;
}

.form-group {
label {
display: none;
Expand All @@ -76,6 +85,14 @@
box-shadow: none;
margin-bottom: 0;
}

&.ng-dirty {
&.ng-invalid {
&:not(.ng-pristine) {
border-bottom: 2px solid red;
}
}
}
}
}

Expand All @@ -88,4 +105,71 @@
box-shadow: none !important;
}
}

&.image-ctnr {
margin: -0.5rem -0.75rem;

.imgc-topbar {
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 1px 1px rgba(0, 0, 0, 0.16);
border-bottom: 0px;

button {
background-color: transparent;

&:hover {
cursor: pointer;
background-color: #f1f1f1;
transition: 0.2s ease;
}
}
}

.imgc-ctnt {
padding: 0.5rem;

.progress {
height: 0.5rem;
margin: 0.5rem -0.5rem -0.6rem -0.5rem;
}

p {
margin: 0;
}

.ngx-insert-img-ph {
border: dashed 2px #bdbdbd;
padding: 1.8rem 0;
position: relative;
letter-spacing: 1px;
text-align: center;

&:hover {
background: #ebebeb;
}

.ngxe-img-upl-frm {
opacity: 0;
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 2147483640;
overflow: hidden;
margin: 0;
padding: 0;
width: 100%;

input {
cursor: pointer;
position: absolute;
right: 0px;
top: 0px;
bottom: 0px;
margin: 0px;
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { HttpClientModule } from '@angular/common/http';
import { NgxEditorToolbarComponent } from './ngx-editor-toolbar.component';
import { ngxEditorConfig } from '../common/ngx-editor.defaults';
import { PopoverModule } from 'ngx-bootstrap';
Expand All @@ -12,7 +13,7 @@ describe('NgxEditorToolbarComponent', () => {

beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [FormsModule, ReactiveFormsModule, PopoverModule.forRoot()],
imports: [FormsModule, ReactiveFormsModule, PopoverModule.forRoot(), HttpClientModule],
declarations: [NgxEditorToolbarComponent],
providers: [CommandExecutorService, MessageService]
})
Expand Down
Loading

0 comments on commit 09b69b5

Please sign in to comment.