Skip to content

Commit

Permalink
Added variable binding (#16)
Browse files Browse the repository at this point in the history
* Added variable binding to markdown-to-html component/directive
* Implemented unit tests
* Updated README.md
  • Loading branch information
jfcere authored Jun 3, 2017
1 parent b37d1b2 commit aa70cdc
Show file tree
Hide file tree
Showing 9 changed files with 259 additions and 26 deletions.
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ ng2-markdown-to-html provides one component and one directive to parse your mark

### Component

You can use `markdown-to-html` component to either parse static markdown directly from your html markup or load the content from a remote url using `src` property.
You can use `markdown-to-html` component to either parse static markdown directly from your html markup, load the content from a remote url using `src` property or bind a variable to your component using `data` property.

```html
<!-- static markdown -->
Expand All @@ -74,6 +74,9 @@ You can use `markdown-to-html` component to either parse static markdown directl

<!-- loaded from remote url -->
<markdown-to-html [src]="'path/to/file.md'"></markdown-to-html>

<!-- variable binding -->
<markdown-to-html [data]="markdown"></markdown-to-html>
```

### Directive
Expand All @@ -88,6 +91,9 @@ The same way the component works, you can use `markdown-to-html` directive to ac

<!-- loaded from remote url -->
<div markdown-to-html [src]="'path/to/file.md'"></div>

<!-- variable binding -->
<div markdown-to-html [data]="markdown"></div>
```

## Synthax highlight
Expand All @@ -112,6 +118,14 @@ When using remote url ng2-markdown-to-html will use file extension to automatica
<markdown-to-html [src]="'path/to/file.php'"></markdown-to-html>
```

When using variable binding you are responsible to provide the code block with related language.

```typescript
public markdown = '```typescript \n'
+ 'const myProp: string = \'value\' \n'
+ '```';
```

## Demo application

A demo is available @ [https://jfcere.github.io/ng2-markdown-to-html](https://jfcere.github.io/ng2-markdown-to-html) and it source code can be found inside the `src/app/markdown-demo` directory.
Expand All @@ -134,7 +148,7 @@ Here is the list of tasks that will be done on this library in a near future ...

- ~~Add CircleCI integration~~
- ~~Publish demo on github pages~~
- Add variable binding feature
- ~~Add variable binding feature~~
- Make Prism highlight optional
- Support Prism.js customizing options (line-numbers, line-height, ...)
- Transpile library to Javascript
Expand Down
17 changes: 14 additions & 3 deletions src/app/markdown-demo/markdown-demo.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ <h4 class="title-based-on">
</header>

<!-- TABLE OF CONTENT -->

<h2 class="subtitle">Table of contents</h2>

<ul>
Expand All @@ -22,6 +21,7 @@ <h2 class="subtitle">Table of contents</h2>
<li><a href="#blockquotes">Blockquotes</a></li>
<li><a href="#horizontal-rule">Horizontal Rule</a></li>
<li><a href="#remote-url">Remote Url</a></li>
<li><a href="#variable-binding">Variable Binding</a></li>
</ul>

<!-- HEADER -->
Expand Down Expand Up @@ -128,7 +128,7 @@ <h2 id="horizontal-rule" class="subtitle">Horizontal Rule</h2>
</markdown-to-html>

<!-- REMOTE URL -->
<h2 id="remote-url" class="subtitle">Remote url</h2>
<h2 id="remote-url" class="subtitle">Remote Url</h2>

<markdown-to-html>
Using component with `src` property to fetch remote markdown file `app/markdown-demo/remote/demo.md`
Expand Down Expand Up @@ -162,4 +162,15 @@ <h2 id="remote-url" class="subtitle">Remote url</h2>
Using directive with `src` property to fetch remote C++ file `app/markdown-demo/remote/demo.cpp`
</markdown-to-html>

<div markdown-to-html [src]="'app/markdown-demo/remote/demo.cpp'"></div>
<div markdown-to-html [src]="'app/markdown-demo/remote/demo.cpp'"></div>

<!-- VARIABLE BINDING -->
<h2 id="variable-binding" class="subtitle">Variable Binding</h2>

<markdown-to-html>
Using component or directive with `data` property allow to bind a variable that will update the DOM when value changes
</markdown-to-html>

<textarea class="variable-textarea" [(ngModel)]="markdown"></textarea>

<markdown-to-html class="variable-binding" [data]="markdown"></markdown-to-html>
21 changes: 21 additions & 0 deletions src/app/markdown-demo/markdown-demo.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,24 @@ header {
margin-bottom: 24px;
padding: 13px;
}

.variable-binding,
.variable-textarea {
width: 49%;

@media (max-width: 900px) {
width: 100%;
}
}

.variable-textarea {
border-radius: 4px;
margin-top: 8px;
min-height: 320px;
padding: 8px;
}

.variable-binding {
display: block;
float: right;
}
38 changes: 27 additions & 11 deletions src/app/markdown-demo/markdown-demo.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,32 @@ import { Component } from '@angular/core';
})
export class MarkdownDemoComponent {
// markdown
public blockquotes = require('raw-loader!./markdown/blockquotes.md');
public codeAndSynthaxHighlighting = require('raw-loader!./markdown/code-and-synthax-highlighting.md');
public emphasis = require('raw-loader!./markdown/emphasis.md');
public headers = require('raw-loader!./markdown/headers.md');
public horizontalRule = require('raw-loader!./markdown/horizontal-rule.md');
public images = require('raw-loader!./markdown/images.md');
public links = require('raw-loader!./markdown/links.md');
public lists = require('raw-loader!./markdown/lists.md');
public listsDot = require('raw-loader!./markdown/lists-dot.md');
public tables = require('raw-loader!./markdown/tables.md');
blockquotes = require('raw-loader!./markdown/blockquotes.md');
codeAndSynthaxHighlighting = require('raw-loader!./markdown/code-and-synthax-highlighting.md');
emphasis = require('raw-loader!./markdown/emphasis.md');
headers = require('raw-loader!./markdown/headers.md');
horizontalRule = require('raw-loader!./markdown/horizontal-rule.md');
images = require('raw-loader!./markdown/images.md');
links = require('raw-loader!./markdown/links.md');
lists = require('raw-loader!./markdown/lists.md');
listsDot = require('raw-loader!./markdown/lists-dot.md');
tables = require('raw-loader!./markdown/tables.md');
// remote
public demoPython = require('raw-loader!./remote/demo.py');
demoPython = require('raw-loader!./remote/demo.py');
// variable-binding
markdown =
`### Markdown example
---
This is an **example** where we bind a variable to the \`markdown-to-html\` component that is also bind to a textarea.
#### example.component.ts
\`\`\`typescript
public markdown = "# Markdown";
\`\`\`
#### example.component.html
\`\`\`html
<textarea [(ngModel)]="markdown"></textarea>
<markdown-to-html [data]="markdown"></markdown-to-html>
\`\`\``;
}
2 changes: 2 additions & 0 deletions src/app/markdown-demo/markdown-demo.module.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';

import { MarkdownDemoComponent } from './markdown-demo.component';
Expand All @@ -7,6 +8,7 @@ import { MarkdownToHtmlModule } from '../markdown-to-html/markdown-to-html.modul
@NgModule({
imports: [
BrowserModule,
FormsModule,
MarkdownToHtmlModule.forRoot(),
],
declarations: [MarkdownDemoComponent],
Expand Down
57 changes: 54 additions & 3 deletions src/app/markdown-to-html/markdown-to-html.component.spec.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HttpModule } from '@angular/http';
import { MarkdownToHtmlComponent } from './markdown-to-html.component';
import { MarkdownToHtmlService } from './markdown-to-html.service';
import * as marked from 'marked';

import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/of';
import 'rxjs/add/operator/toPromise';

import * as marked from 'marked';
import * as Prism from 'prismjs';

import { MarkdownToHtmlComponent } from './markdown-to-html.component';
import { MarkdownToHtmlService } from './markdown-to-html.service';

class MockMarkdownToHtmlService extends MarkdownToHtmlService {
getSource(src: string): Observable<string> {
return Observable.of('');
Expand Down Expand Up @@ -39,6 +43,16 @@ describe('MarkdownToHtmlComponent', () => {

describe('ngAfterViewInit', () => {

it('should call handleData method when data is provided', () => {

spyOn(component, 'handleData');

component.data = '# Markdown';
component.ngAfterViewInit();

expect(component.handleData).toHaveBeenCalled();
});

it('should call handleSrc method when src is provided', () => {

spyOn(component, 'handleSrc');
Expand All @@ -65,6 +79,28 @@ describe('MarkdownToHtmlComponent', () => {

describe('ngOnChanges', () => {

it('should call handleData method when data is changed', () => {

spyOn(component, 'handleData');

const mockSimpleChanges = { data: null };

component.ngOnChanges(mockSimpleChanges);

expect(component.handleData).toHaveBeenCalled();
});

it('should not call handleData method when data is unchanged', () => {

spyOn(component, 'handleData');

const mockSimpleChanges = {};

component.ngOnChanges(mockSimpleChanges);

expect(component.handleData).not.toHaveBeenCalled();
});

it('should call handleSrc method when src is changed', () => {

spyOn(component, 'handleSrc');
Expand All @@ -88,6 +124,21 @@ describe('MarkdownToHtmlComponent', () => {
});
});

describe('handleData', () => {

it('should call handleRaw method with data parameter', () => {

spyOn(component, 'handleRaw');

const mockData = '# Markdown';

component.data = mockData;
component.handleData();

expect(component.handleRaw).toHaveBeenCalledWith(mockData);
});
});

describe('handleSrc', () => {

it('should call getSource from MarkdownToHtmlService', () => {
Expand Down
23 changes: 19 additions & 4 deletions src/app/markdown-to-html/markdown-to-html.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import 'prismjs/components/prism-typescript';
styleUrls: ['./markdown-to-html.component.scss'],
})
export class MarkdownToHtmlComponent implements AfterViewInit, OnChanges {
@Input() data: string;
@Input() src: string;

constructor(
Expand All @@ -33,25 +34,38 @@ export class MarkdownToHtmlComponent implements AfterViewInit, OnChanges {
) { }

ngAfterViewInit() {
if (this.data) {
this.handleData();
return;
}
if (this.src) {
this.handleSrc();
} else {
this.handleRaw(this.element.nativeElement.innerHTML);
return;
}
this.handleRaw(this.element.nativeElement.innerHTML);
}

// SimpleChanges parameter is required for AoT compilation (do not remove)
ngOnChanges(changes: SimpleChanges) {
if ('data' in changes) {
this.handleData();
return;
}
if ('src' in changes) {
this.handleSrc();
return;
}
}

handleData() {
this.handleRaw(this.data);
}

handleSrc() {
const extension = this.src
? this.src.split('.').splice(-1).join()
: null;
return this.mthService.getSource(this.src)
this.mthService.getSource(this.src)
.subscribe(data => {
const raw = extension !== 'md'
? '```' + extension + '\n' + data + '\n```'
Expand All @@ -73,7 +87,8 @@ export class MarkdownToHtmlComponent implements AfterViewInit, OnChanges {
let indentStart: number;
return raw
.replace(/\&gt;/g, '>')
.split('\n').map((line: string) => {
.split('\n')
.map((line: string) => {
// find position of 1st non-whitespace character
// to determine the markdown indentation start
if (line.length > 0 && isNaN(indentStart)) {
Expand Down
7 changes: 6 additions & 1 deletion src/app/markdown-to-html/markdown-to-html.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ import { MarkdownToHtmlService } from './markdown-to-html.service';
exports: [MarkdownToHtmlComponent],
imports: [HttpModule],
declarations: [MarkdownToHtmlComponent],
providers: [MarkdownToHtmlService],
})
export class MarkdownToHtmlModule {
static forRoot(): ModuleWithProviders {
return {
ngModule: MarkdownToHtmlModule,
providers: [MarkdownToHtmlService],
};
}
static forChild(): ModuleWithProviders {
return {
ngModule: MarkdownToHtmlModule,
};
Expand Down
Loading

0 comments on commit aa70cdc

Please sign in to comment.