Skip to content

Commit

Permalink
feat: add mode parament (#13)
Browse files Browse the repository at this point in the history
  • Loading branch information
cipchk committed Nov 27, 2020
1 parent 49c89fc commit 2e8304b
Show file tree
Hide file tree
Showing 12 changed files with 194 additions and 117 deletions.
2 changes: 1 addition & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"printWidth": 80,
"printWidth": 140,
"singleQuote": true,
"trailingComma": "all"
}
68 changes: 57 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
Angular for syntax highlighting with highlight.js

[![NPM version](https://img.shields.io/npm/v/ngx-highlight-js.svg)](https://www.npmjs.com/package/ngx-highlight-js)
[![Build Status](https://travis-ci.org/cipchk/ngx-highlight-js.svg?branch=master)](https://travis-ci.org/cipchk/ngx-highlight-js)

[![Ci](https://github.com/cipchk/ngx-highlight-js/workflows/Ci/badge.svg)](https://github.com/cipchk/ngx-highlight-js/actions)

## Demo

Expand Down Expand Up @@ -35,34 +34,81 @@ export class AppModule {
Load the highlight.js and theme css in page.

```html
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/highlight.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js"></script>
```

```html
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/9.18.1/styles/atom-one-dark.min.css">
<link rel="stylesheet" href="//cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/styles/atom-one-dark.min.css" />
```

## Only `<textarea>` Tag
## Usage
### Simple mode

```html
<textarea highlight-js [options]="{}" [lang]="'typescript'">
/* tslint:disable */
import { Component } from '@angular/core';

@Component({
selector: 'demo',
templateUrl: './demo.component.html',
styleUrls: ['./demo.component.scss']
selector: 'demo',
templateUrl: './demo.component.html',
styleUrls: ['./demo.component.scss']
})
export class DemoComponent {
switchStatus: boolean = true;
switchStatus: boolean = true;
}
</textarea>
```

**[options]** equar [configure(options)](http://highlightjs.readthedocs.io/en/latest/api.html#configure-options). (optional)
### Default mode

Will render each `<pre><code>`:

```html
<textarea highlight-js mode="default">
<p>
The bare minimum for using highlight.js on a web page is linking to the library along with one of the styles and calling
<a href="http://highlightjs.readthedocs.io/en/latest/api.html#inithighlightingonload"><code>initHighlightingOnLoad</code></a
>:
</p>
<pre><code class="language-html">&lt;link rel=&quot;stylesheet&quot; href=&quot;/path/to/styles/default.css&quot;&gt;
&lt;script src=&quot;/path/to/highlight.min.js&quot;&gt;&lt;/script&gt;
&lt;script&gt;hljs.initHighlightingOnLoad();&lt;/script&gt;
</code></pre>
<p>
This will find and highlight code inside of <code>&lt;pre&gt;&lt;code&gt;</code> tags; it tries to detect the language automatically. If
automatic detection doesn’t work for you, you can specify the language in the <code>class</code> attribute:
</p>
<pre><code class="language-html">&lt;pre&gt;&lt;code class=&quot;html&quot;&gt;...&lt;/code&gt;&lt;/pre&gt;
</code></pre>
</textarea>
```

### Parameter

**[lang]** uses language detection by default but you can specify the language. (optional)
| Property | Description | Type | Default | Global Config |
|----------|-------------|------|---------|---------------|
| `[mode]` | - `default` Will render each `<pre><code>`<br>- `simple` Render all content according to `lang` language | `default, simple` | `simple` ||
| `[options]` | Equar [configure(options)](http://highlightjs.readthedocs.io/en/latest/api.html#configure-options) | `any` | - ||
| `[lang]` | Uses language detection by default but you can specify the language | `string` | `html` ||
| `[code]` | Specify content | `string` | `html` | - |

**Global Config**

```ts
@NgModule({
providers: [
{
provide: HIGHLIGHTJS_CONFIG,
useValue: {
lang: 'html'
} as HighlightJsConfig
}
],
imports: [ HighlightJsModule ],
})
export class AppDemoModule {}
```

## Troubleshooting

Expand Down
2 changes: 1 addition & 1 deletion lib/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-highlight-js",
"version": "11.0.0",
"version": "11.1.0",
"description": "Angular for syntax highlighting with highlight.js",
"keywords": [
"highlight",
Expand Down
1 change: 1 addition & 0 deletions lib/public_api.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export { HighlightJsDirective } from './src/highlight-js.directive';
export * from './src/highlight-js.module';
export * from './src/highlight-js.config';
20 changes: 20 additions & 0 deletions lib/src/highlight-js.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { InjectionToken } from '@angular/core';

export interface HighlightJsConfig {
/**
* Specify rendering mode
* - `default` Will render each `<pre><code>`
* - `simple` Render all content according to `lang` language
*/
mode?: 'default' | 'simple';
/**
* Uses language detection by default but you can specify the language
*/
lang?: string;
/**
* Equar [configure(options)](http://highlightjs.readthedocs.io/en/latest/api.html#configure-options)
*/
options?: any;
}

export const HIGHLIGHTJS_CONFIG = new InjectionToken<HighlightJsConfig>('HighlightJs-Config');
82 changes: 40 additions & 42 deletions lib/src/highlight-js.directive.ts
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
import {
Directive,
ElementRef,
Input,
OnInit,
OnDestroy,
AfterViewInit,
Inject,
Optional,
} from '@angular/core';
import { Directive, ElementRef, Input, OnDestroy, AfterViewInit, Inject, Optional } from '@angular/core';
import { DOCUMENT } from '@angular/common';
import { NgModel } from '@angular/forms';
import { Subscription } from 'rxjs';
import { HighlightJsConfig, HIGHLIGHTJS_CONFIG } from './highlight-js.config';

declare const hljs: any;

@Directive({
selector: '[highlight-js]',
host: {
'[style.display]': `'none'`,
'[style.display]': `mode === 'simple' ? 'none' : null`,
},
exportAs: 'highlightJs',
})
export class HighlightJsDirective implements OnInit, AfterViewInit, OnDestroy {
constructor(
private el: ElementRef<HTMLElement>,
@Optional() private ngModel: NgModel,
@Inject(DOCUMENT) private doc: any,
) {}
export class HighlightJsDirective implements AfterViewInit, OnDestroy {
@Input() options: any;
@Input() lang = 'html';
@Input() code!: string;
@Input() mode: 'default' | 'simple' = 'simple';

protected codeEl?: HTMLElement;
protected parentEl!: HTMLElement;
private modelValue$?: Subscription;

// #region Mutation

private observer!: MutationObserver;

constructor(
private el: ElementRef<HTMLElement>,
@Optional() private ngModel: NgModel,
@Inject(DOCUMENT) private doc: any,
@Optional() @Inject(HIGHLIGHTJS_CONFIG) cog: HighlightJsConfig,
) {
Object.assign(this, cog);
}

private escapeHTML(str: string): string {
return (str || '')
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&apos;');
return (str || '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&apos;');
}

private init(): void {
this.destroy();
this.codeEl = this.doc.createElement('pre') as HTMLElement;
if (this.lang) {
this.codeEl.className = this.lang;
const el = this.el.nativeElement;
const code = this.code || '' + el.innerHTML.trim();
this.codeEl = this.doc.createElement(this.mode === 'default' ? 'div' : 'pre') as HTMLElement;
const isSimple = this.mode === 'simple';
if (isSimple) {
if (this.lang) {
this.codeEl.className = this.lang;
}
this.parentEl = el.parentNode as HTMLElement;
this.parentEl.insertBefore(this.codeEl, el.nextSibling);
} else {
this.parentEl = el;
this.parentEl.innerHTML = ``;
this.parentEl.appendChild(this.codeEl);
}
this.codeEl.innerHTML =
this.code || '' + this.el.nativeElement.innerHTML.trim();
this.parentEl = this.el.nativeElement.parentNode as HTMLElement;
this.parentEl.insertBefore(this.codeEl, this.el.nativeElement.nextSibling);

this.codeEl.innerHTML = code;
hljs.configure({ ...this.options });
hljs.highlightBlock(this.codeEl);

if (isSimple) {
hljs.highlightBlock(this.codeEl);
} else {
this.codeEl.querySelectorAll('pre code').forEach((block) => {
hljs.highlightBlock(block);
});
}
}

private destroy(): void {
if (this.codeEl) {
if (this.codeEl && this.parentEl) {
this.parentEl.removeChild(this.codeEl);
this.codeEl = undefined;
}
}

ngOnInit(): void {
this.init();
}

ngAfterViewInit(): void {
this.init();
if (this.ngModel) {
this.modelValue$ = this.ngModel.valueChanges?.subscribe((res) => {
this.code = this.escapeHTML(res);
Expand Down Expand Up @@ -111,6 +111,4 @@ export class HighlightJsDirective implements OnInit, AfterViewInit, OnDestroy {
}
this.observer.disconnect();
}

// #endregionn
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ngx-highlight-js",
"version": "11.0.0",
"version": "11.1.0",
"description": "Angular for syntax highlighting with highlight.js",
"keywords": [
"highlight",
Expand Down
3 changes: 2 additions & 1 deletion src/app/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { HighlightJsModule } from 'ngx-highlight-js';
import { HighlightJsConfig, HighlightJsModule, HIGHLIGHTJS_CONFIG } from 'ngx-highlight-js';

import { AppComponent } from './app.component';
import { DemoComponent } from './components/demo.component';

@NgModule({
providers: [{ provide: HIGHLIGHTJS_CONFIG, useValue: { lang: 'html' } as HighlightJsConfig }],
imports: [BrowserModule, FormsModule, HighlightJsModule],
declarations: [AppComponent, DemoComponent],
bootstrap: [AppComponent],
Expand Down
43 changes: 18 additions & 25 deletions src/app/components/demo.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@
<div class="col-sm-12">
<h5 class="mt-3 mb-3">Installation instructions</h5>
<h6 class="mb-2">1、Install</h6>
<textarea highlight-js [lang]="'bash'">
npm install --save ngx-highlight-js</textarea
>
<textarea highlight-js [lang]="'bash'">npm install --save ngx-highlight-js</textarea>
</div>
<div class="col-sm-12">
<h6 class="mb-2">
2、Import the `HighlightJsModule` in to your root `AppModule`.
</h6>
<h6 class="mb-2">2、Import the `HighlightJsModule` in to your root `AppModule`.</h6>
<textarea highlight-js lang="ts">
import { HighlightJsModule } from 'ngx-highlight-js';
@NgModule({
Expand Down Expand Up @@ -53,35 +49,24 @@ <h5 class="mt-5 mb-3">Only `&lt;textarea>` Tag</h5>
&lt;/textarea>
</textarea
>
<button
class="btn btn-primary btn-sm mb-3"
(click)="switchStatus = !switchStatus"
>
<button class="btn btn-primary btn-sm mb-3" (click)="switchStatus = !switchStatus">
{{ switchStatus ? 'Hide' : 'Show' }}
</button>
</div>
<div class="col-sm-6">
<p>
<strong>[options]</strong> equar
<a
href="http://highlightjs.readthedocs.io/en/latest/api.html#configure-options"
target="_blank"
>configure(options)</a
>. (optional)
</p>
<p>
<strong>[lang]</strong> uses language detection by default but you can
specify the language. (optional)
<a href="http://highlightjs.readthedocs.io/en/latest/api.html#configure-options" target="_blank">configure(options)</a>.
(optional)
</p>
<p><strong>[lang]</strong> uses language detection by default but you can specify the language. (optional)</p>
</div>
</div>
<h5 class="mt-5 mb-3">Support `ngModel`</h5>
<div class="row">
<div class="col-sm-6">
<textarea highlight-js [lang]="'html'" [ngModel]="html"></textarea>
<button class="btn btn-primary btn-sm mb-3" (click)="updateHTML()">
Update
</button>
<button class="btn btn-primary btn-sm mb-3" (click)="updateHTML()">Update</button>
</div>
</div>
<h5 class="mt-5 mb-3">Observe Content</h5>
Expand All @@ -90,9 +75,17 @@ <h5 class="mt-5 mb-3">Observe Content</h5>
<textarea highlight-js [lang]="'html'">
{{ random }}
</textarea>
<button class="btn btn-primary btn-sm mb-3" (click)="randomHtml()">
Random Html
</button>
<button class="btn btn-primary btn-sm mb-3" (click)="randomHtml()">Random Html</button>
</div>
</div>
<h5 class="mt-5 mb-3">Default mode</h5>
<div class="row">
<div class="col-sm-6">
<p>Should be will render each &lt;pre>&lt;code></p>
<textarea highlight-js>&lt;div [innerHTML]="code" highlight-js mode="default">&lt;/div></textarea>
<hr />
<h6>Result</h6>
<div [innerHTML]="code" highlight-js mode="default"></div>
</div>
</div>
<p class="mt-5 mb-5">
Expand Down
Loading

0 comments on commit 2e8304b

Please sign in to comment.