wip: tweaks to website
This commit is contained in:
parent
4f607633dd
commit
f72ee2ea46
18 changed files with 315 additions and 330 deletions
|
|
@ -8,13 +8,13 @@ jobs:
|
||||||
- checkout
|
- checkout
|
||||||
- restore_cache:
|
- restore_cache:
|
||||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||||
- run: npm install
|
- run: yarn
|
||||||
- save_cache:
|
- save_cache:
|
||||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||||
paths:
|
paths:
|
||||||
- ./node_modules
|
- ./node_modules
|
||||||
- run: npm run coverage
|
- run: yarn run build
|
||||||
- run: npm run check-coverage
|
- run: yarn run coverage
|
||||||
|
|
||||||
build-latest: &latest-build
|
build-latest: &latest-build
|
||||||
docker:
|
docker:
|
||||||
|
|
@ -29,6 +29,7 @@ jobs:
|
||||||
key: dependency-cache-{{ checksum "yarn.lock" }}
|
key: dependency-cache-{{ checksum "yarn.lock" }}
|
||||||
paths:
|
paths:
|
||||||
- ./node_modules
|
- ./node_modules
|
||||||
|
- run: yarn run build
|
||||||
- run: yarn run lint
|
- run: yarn run lint
|
||||||
- run: yarn run coverage
|
- run: yarn run coverage
|
||||||
- run: yarn run codacy
|
- run: yarn run codacy
|
||||||
|
|
@ -38,40 +39,25 @@ jobs:
|
||||||
- docs
|
- docs
|
||||||
- build
|
- build
|
||||||
|
|
||||||
build-node_4:
|
|
||||||
<<: *common-build
|
|
||||||
docker:
|
|
||||||
- image: node:4
|
|
||||||
|
|
||||||
build-node_5:
|
|
||||||
<<: *common-build
|
|
||||||
docker:
|
|
||||||
- image: node:5
|
|
||||||
|
|
||||||
build-node_6:
|
|
||||||
<<: *common-build
|
|
||||||
docker:
|
|
||||||
- image: node:6
|
|
||||||
|
|
||||||
build-node_7:
|
|
||||||
<<: *common-build
|
|
||||||
docker:
|
|
||||||
- image: node:7
|
|
||||||
|
|
||||||
build-node_8:
|
build-node_8:
|
||||||
<<: *common-build
|
<<: *common-build
|
||||||
docker:
|
docker:
|
||||||
- image: node:8
|
- image: node:8
|
||||||
|
|
||||||
build-node_9:
|
build-node_10:
|
||||||
<<: *common-build
|
<<: *common-build
|
||||||
docker:
|
docker:
|
||||||
- image: node:9
|
- image: node:10
|
||||||
|
|
||||||
build-node_10:
|
build-node_11:
|
||||||
|
<<: *common-build
|
||||||
|
docker:
|
||||||
|
- image: node:11
|
||||||
|
|
||||||
|
build-node_12:
|
||||||
<<: *latest-build
|
<<: *latest-build
|
||||||
docker:
|
docker:
|
||||||
- image: node:10
|
- image: node:12
|
||||||
|
|
||||||
deploy:
|
deploy:
|
||||||
machine:
|
machine:
|
||||||
|
|
@ -89,16 +75,13 @@ workflows:
|
||||||
version: 2
|
version: 2
|
||||||
build:
|
build:
|
||||||
jobs:
|
jobs:
|
||||||
- build-node_4
|
|
||||||
- build-node_5
|
|
||||||
- build-node_6
|
|
||||||
- build-node_7
|
|
||||||
- build-node_8
|
- build-node_8
|
||||||
- build-node_9
|
|
||||||
- build-node_10
|
- build-node_10
|
||||||
|
- build-node_11
|
||||||
|
- build-node_12
|
||||||
- deploy:
|
- deploy:
|
||||||
requires:
|
requires:
|
||||||
- build-node_10
|
- build-node_12
|
||||||
filters:
|
filters:
|
||||||
branches:
|
branches:
|
||||||
only: master
|
only: master
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,7 @@
|
||||||
"es6": true,
|
"es6": true,
|
||||||
"node": true,
|
"node": true,
|
||||||
"browser": true,
|
"browser": true,
|
||||||
"commonjs": true,
|
"commonjs": true
|
||||||
"jquery": true,
|
|
||||||
"phantomjs": true,
|
|
||||||
"jasmine": true,
|
|
||||||
"mocha": true,
|
|
||||||
"amd": true,
|
|
||||||
"worker": true,
|
|
||||||
"qunit": true
|
|
||||||
},
|
},
|
||||||
"plugins": ["standard", "node", "import", "promise", "@typescript-eslint", "jest"],
|
"plugins": ["standard", "node", "import", "promise", "@typescript-eslint", "jest"],
|
||||||
"globals": {
|
"globals": {
|
||||||
|
|
|
||||||
199
README.md
199
README.md
|
|
@ -1,9 +1,8 @@
|
||||||
# diff2html
|
# diff2html
|
||||||
|
|
||||||
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
|
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
|
||||||
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
|
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
|
||||||
[](https://circleci.com/gh/rtfpessoa/diff2html)
|
[](https://circleci.com/gh/rtfpessoa/diff2html)
|
||||||
[](https://dependencyci.com/github/rtfpessoa/diff2html)
|
|
||||||
|
|
||||||
[](https://www.npmjs.com/package/diff2html)
|
[](https://www.npmjs.com/package/diff2html)
|
||||||
[](https://david-dm.org/rtfpessoa/diff2html)
|
[](https://david-dm.org/rtfpessoa/diff2html)
|
||||||
|
|
@ -22,21 +21,21 @@ diff2html generates pretty HTML diffs from git or unified diff output.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
* Supports git and unified diffs
|
- Supports git and unified diffs
|
||||||
|
|
||||||
* Line by line and Side by side diff
|
- Line by line and Side by side diff
|
||||||
|
|
||||||
* New and old line numbers
|
- New and old line numbers
|
||||||
|
|
||||||
* Inserted and removed lines
|
- Inserted and removed lines
|
||||||
|
|
||||||
* GitHub like style
|
- GitHub like style
|
||||||
|
|
||||||
* Code syntax highlight
|
- Code syntax highlight
|
||||||
|
|
||||||
* Line similarity matching
|
- Line similarity matching
|
||||||
|
|
||||||
* Easy code selection
|
- Easy code selection
|
||||||
|
|
||||||
## Online Example
|
## Online Example
|
||||||
|
|
||||||
|
|
@ -44,15 +43,15 @@ diff2html generates pretty HTML diffs from git or unified diff output.
|
||||||
|
|
||||||
## Distributions
|
## Distributions
|
||||||
|
|
||||||
* [WebJar](http://www.webjars.org/)
|
- [WebJar](http://www.webjars.org/)
|
||||||
|
- [Node Module](https://www.npmjs.org/package/diff2html)
|
||||||
* [Node Module](https://www.npmjs.org/package/diff2html)
|
- [Node CLI](https://www.npmjs.org/package/diff2html-cli)
|
||||||
|
- Manually download and import:
|
||||||
* [Bower Package](http://bower.io/search/?q=diff2html)
|
- Browser
|
||||||
|
- [build/browser/diff2html.min.js](./build/browser/diff2html.min.js) - includes the diff parser and html generator
|
||||||
* [Node CLI](https://www.npmjs.org/package/diff2html-cli)
|
- [build/browser/diff2html-ui.min.js](./build/browser/diff2html-ui.min.js) - includes the wrapper of diff2html that adds highlight, synchronized scroll, and other nice features
|
||||||
|
- Node.js
|
||||||
* Manually download and import [dist/diff2html.min.js](./dist/diff2html.min.js) into your page
|
- [build/commonjs-node/diff2html.js](./build/commonjs-node/diff2html.js) - includes the diff parser and html generator
|
||||||
|
|
||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
|
|
@ -62,7 +61,7 @@ Import the stylesheet
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="dist/diff2html.css">
|
<link rel="stylesheet" type="text/css" href="dist/diff2html.css" />
|
||||||
```
|
```
|
||||||
|
|
||||||
You can also refer to it from a CDN like [CDNJS](https://cdnjs.com/libraries/diff2html).
|
You can also refer to it from a CDN like [CDNJS](https://cdnjs.com/libraries/diff2html).
|
||||||
|
|
@ -73,37 +72,41 @@ Import the stylesheet and the library code
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="dist/diff2html.css">
|
<link rel="stylesheet" type="text/css" href="build/css/diff2html.min.css" />
|
||||||
|
|
||||||
<!-- Javascripts -->
|
<!-- Javascripts -->
|
||||||
<script type="text/javascript" src="dist/diff2html.js"></script>
|
<script type="text/javascript" src="build/browser/diff2html.min.js"></script>
|
||||||
```
|
```
|
||||||
|
|
||||||
It will now be available as a global variable named `Diff2Html`.
|
It will now be available as a global variable named `global.Diff2Html`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var diffHtml = Diff2Html.getPrettyHtml(
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
'<Unified Diff String>',
|
var diffHtml = global.Diff2Html.html("<Unified Diff String>", {
|
||||||
{inputFormat: 'diff', showFiles: true, matching: 'lines', outputFormat: 'side-by-side'}
|
drawFileList: true,
|
||||||
);
|
matching: "lines",
|
||||||
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
outputFormat: "side-by-side"
|
||||||
|
});
|
||||||
|
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
### Node Module
|
### Node Module
|
||||||
|
|
||||||
```js
|
```js
|
||||||
let diff2html = require("diff2html").Diff2Html
|
const Diff2html = require("diff2html");
|
||||||
|
const diffJson = Diff2html.parse("<Unified Diff String>");
|
||||||
|
const diffHtml = Diff2html.html(diffJson, { drawFileList: true });
|
||||||
|
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
||||||
```
|
```
|
||||||
|
|
||||||
### Angular
|
### Angular
|
||||||
|
|
||||||
* Typescript
|
- Typescript
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
// import diff2html
|
import * as Diff2Html from "diff2html";
|
||||||
import {Diff2Html} from 'diff2html'
|
import { Component, OnInit } from "@angular/core";
|
||||||
import {Component, OnInit} from '@angular/core';
|
|
||||||
|
|
||||||
|
|
||||||
export class AppDiffComponent implements OnInit {
|
export class AppDiffComponent implements OnInit {
|
||||||
outputHtml: string;
|
outputHtml: string;
|
||||||
|
|
@ -111,18 +114,18 @@ export class AppDiffComponent implements OnInit {
|
||||||
this.init();
|
this.init();
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {}
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
let strInput = "--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n";
|
let strInput =
|
||||||
let outputHtml = Diff2Html.getPrettyHtml(strInput, {inputFormat: 'diff', showFiles: true, matching: 'lines'});
|
"--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n";
|
||||||
|
let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: "lines" });
|
||||||
this.outputHtml = outputHtml;
|
this.outputHtml = outputHtml;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
* HTML
|
- HTML
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -136,7 +139,7 @@ export class AppDiffComponent implements OnInit {
|
||||||
</html>
|
</html>
|
||||||
```
|
```
|
||||||
|
|
||||||
* `.angular-cli.json` - Add styles
|
- `.angular-cli.json` - Add styles
|
||||||
|
|
||||||
```json
|
```json
|
||||||
"styles": [
|
"styles": [
|
||||||
|
|
@ -152,20 +155,21 @@ export class AppDiffComponent implements OnInit {
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import { Diff2Html } from "diff2html";
|
import * as Diff2Html from "diff2html";
|
||||||
import "diff2html/dist/diff2html.min.css";
|
import "diff2html/build/css/diff2html.min.css";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
diffs: "--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n"
|
diffs:
|
||||||
|
"--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n"
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
prettyHtml() {
|
prettyHtml() {
|
||||||
return Diff2Html.getPrettyHtml(this.diffs, {
|
return Diff2Html.getPrettyHtml(this.diffs, {
|
||||||
inputFormat: "diff",
|
inputFormat: "diff",
|
||||||
showFiles: true,
|
drawFileList: true,
|
||||||
matching: "lines",
|
matching: "lines",
|
||||||
outputFormat: "side-by-side"
|
outputFormat: "side-by-side"
|
||||||
});
|
});
|
||||||
|
|
@ -185,41 +189,40 @@ export default {
|
||||||
|
|
||||||
getPrettyHtml(input: any, configuration?: Options): string
|
getPrettyHtml(input: any, configuration?: Options): string
|
||||||
|
|
||||||
> Check out the [src/diff2html.d.ts](./src/diff2html.d.ts) for a complete API definition in TypeScript.
|
|
||||||
|
|
||||||
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The HTML output accepts a Javascript object with configuration. Possible options:
|
The HTML output accepts a Javascript object with configuration. Possible options:
|
||||||
|
|
||||||
- `inputFormat`: the format of the input data: `'diff'` or `'json'`, default is `'diff'`
|
- `inputFormat`: the format of the input data: `'diff'` or `'json'`, default is `'diff'`
|
||||||
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
|
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
|
||||||
- `showFiles`: show a file list before the diff: `true` or `false`, default is `false`
|
- `drawFileList`: show a file list before the diff: `true` or `false`, default is `false`
|
||||||
- `diffStyle`: show differences level in each line: `word` or `char`, default is `word`
|
- `diffStyle`: show differences level in each line: `word` or `char`, default is `word`
|
||||||
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default is `none`
|
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default is `none`
|
||||||
- `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
|
- `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
|
||||||
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500`
|
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500`
|
||||||
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison, default is `200`
|
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison, default is `200`
|
||||||
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
|
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
|
||||||
- `compiledTemplates`: object with previously compiled templates to replace parts of the html
|
- `compiledTemplates`: object with previously compiled templates to replace parts of the html
|
||||||
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
|
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
|
||||||
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is `false`
|
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is `false`
|
||||||
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
||||||
|
|
||||||
** Diff2HtmlUI Helper Options **
|
** Diff2HtmlUI Helper Options **
|
||||||
- `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `false`
|
|
||||||
|
- `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `false`
|
||||||
|
|
||||||
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
||||||
|
|
||||||
|
|
||||||
## Diff2HtmlUI Helper
|
## Diff2HtmlUI Helper
|
||||||
|
|
||||||
> Simple wrapper to ease simple tasks in the browser such as: code highlight and js effects
|
> Simple wrapper to ease simple tasks in the browser such as: code highlight and js effects
|
||||||
|
|
||||||
* Invoke Diff2html
|
- Invoke Diff2html
|
||||||
* Inject output in DOM element
|
- Inject output in DOM element
|
||||||
* Enable collapsible file summary list
|
- Enable collapsible file summary list
|
||||||
* Enable syntax highlight of the code in the diffs
|
- Enable syntax highlight of the code in the diffs
|
||||||
|
|
||||||
### How to use
|
### How to use
|
||||||
|
|
||||||
|
|
@ -227,52 +230,56 @@ The HTML output accepts a Javascript object with configuration. Possible options
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- CSS -->
|
<!-- CSS -->
|
||||||
<link rel="stylesheet" type="text/css" href="dist/diff2html.css">
|
<link rel="stylesheet" type="text/css" href="build/css/diff2html.min.css" />
|
||||||
|
|
||||||
<!-- Javascripts -->
|
<!-- Javascripts -->
|
||||||
<script type="text/javascript" src="dist/diff2html.js"></script>
|
<script type="text/javascript" src="build/browser/diff2html-ui.min.js"></script>
|
||||||
<script type="text/javascript" src="dist/diff2html-ui.js"></script>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Init
|
#### Init
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var diff2htmlUi = new Diff2HtmlUI({diff: diffString});
|
const targetElement = document.getElementById("destination-elem-id");
|
||||||
|
const configuration = { drawFileList: true, matching: "lines" };
|
||||||
|
|
||||||
|
const diff2htmlUi = new global.Diff2HtmlUI(diffString, targetElement, configuration);
|
||||||
// or
|
// or
|
||||||
var diff2htmlUi = new Diff2HtmlUI({json: diffJson});
|
const diff2htmlUi = new global.Diff2HtmlUI(diffJson, targetElement, configuration);
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Draw
|
#### Draw
|
||||||
|
|
||||||
```js
|
```js
|
||||||
diff2htmlUi.draw('html-target-elem', {inputFormat: 'json', showFiles: true, matching: 'lines'});
|
diff2htmlUi.draw();
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Syntax Highlight
|
#### Syntax Highlight
|
||||||
|
|
||||||
> Add the dependencies.
|
|
||||||
Choose one color scheme, and add the main highlight code. Note that the stylesheet for the color scheme must come **before** the main diff2html stylesheet.
|
|
||||||
If your favourite language is not included in the default package also add its javascript highlight file.
|
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Stylesheet -->
|
<!-- Stylesheet -->
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css">
|
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="dist/diff2html.css">
|
<link rel="stylesheet" type="text/css" href="build/css/diff2html.min.css" />
|
||||||
|
|
||||||
<!-- Javascripts -->
|
<!-- Javascripts -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"></script>
|
<script type="text/javascript" src="build/browser/diff2html-ui.min.js"></script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/highlight.min.js"></script>
|
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/languages/scala.min.js"></script>
|
|
||||||
<script type="text/javascript" src="dist/diff2html-ui.js"></script>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> Invoke the Diff2HtmlUI helper
|
> Pass the option `highlight` with value true or invoke `diff2htmlUi.highlightCode()` after `diff2htmlUi.draw()`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$(document).ready(function() {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
var diff2htmlUi = new Diff2HtmlUI({diff: lineDiffExample});
|
const diffString = `diff --git a/sample.js b/sample.js
|
||||||
diff2htmlUi.draw('#line-by-line', {inputFormat: 'json', showFiles: true, matching: 'lines'});
|
index 0000001..0ddf2ba
|
||||||
diff2htmlUi.highlightCode('#line-by-line');
|
--- a/sample.js
|
||||||
|
+++ b/sample.js
|
||||||
|
@@ -1 +1 @@
|
||||||
|
-console.log("Hello World!")
|
||||||
|
+console.log("Hello from Diff2Html!")`;
|
||||||
|
const targetElement = document.getElementById("myDiffElement");
|
||||||
|
const configuration = { inputFormat: "json", drawFileList: true, matching: "lines", highlight: true };
|
||||||
|
const diff2htmlUi = new global.Diff2HtmlUI(diffString, targetElement, configuration);
|
||||||
|
diff2htmlUi.draw();
|
||||||
|
diff2htmlUi.highlightCode();
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -282,17 +289,18 @@ $(document).ready(function() {
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<!-- Javascripts -->
|
<!-- Javascripts -->
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.2.3/jquery.js"></script>
|
<script type="text/javascript" src="build/browser/diff2html-ui.min.js"></script>
|
||||||
<script type="text/javascript" src="dist/diff2html-ui.js"></script>
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> Invoke the Diff2HtmlUI helper
|
> Invoke the Diff2HtmlUI helper
|
||||||
|
> Pass the option `fileListToggle` with value true or invoke `diff2htmlUi.fileListToggle()` after `diff2htmlUi.draw()`.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
$(document).ready(function() {
|
document.addEventListener("DOMContentLoaded", () => {
|
||||||
var diff2htmlUi = new Diff2HtmlUI({diff: lineDiffExample});
|
const targetElement = document.getElementById("myDiffElement");
|
||||||
diff2htmlUi.draw('#line-by-line', {inputFormat: 'json', showFiles: true, matching: 'lines'});
|
var diff2htmlUi = new global.Diff2HtmlUI(lineDiffExample, targetElement, { drawFileList: true, matching: "lines" });
|
||||||
diff2htmlUi.fileListCloseable('#line-by-line', false);
|
diff2htmlUi.draw();
|
||||||
|
diff2htmlUi.fileListToggle(false);
|
||||||
});
|
});
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -301,11 +309,13 @@ $(document).ready(function() {
|
||||||
### 1. Out of memory or Slow execution
|
### 1. Out of memory or Slow execution
|
||||||
|
|
||||||
#### Causes:
|
#### Causes:
|
||||||
* Big files
|
|
||||||
* Big lines
|
- Big files
|
||||||
|
- Big lines
|
||||||
|
|
||||||
#### Fix:
|
#### Fix:
|
||||||
* Disable the line matching algorithm, by setting the option `{"matching": "none"}` when invoking diff2html
|
|
||||||
|
- Disable the line matching algorithm, by setting the option `{"matching": "none"}` when invoking diff2html
|
||||||
|
|
||||||
## Contributions
|
## Contributions
|
||||||
|
|
||||||
|
|
@ -355,6 +365,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
||||||
|
|
||||||
<!-- markdownlint-enable -->
|
<!-- markdownlint-enable -->
|
||||||
<!-- prettier-ignore-end -->
|
<!-- prettier-ignore-end -->
|
||||||
|
|
||||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||||
|
|
||||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,12 @@
|
||||||
"url": "https://www.github.com/rtfpessoa/diff2html/issues"
|
"url": "https://www.github.com/rtfpessoa/diff2html/issues"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": "8.* || >=10"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
|
"lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
|
||||||
"style": "yarn run lint",
|
"style": "yarn run lint",
|
||||||
"test": "jest",
|
"test": "yarn run build-scripts && yarn run build-templates && jest",
|
||||||
"coverage": "jest --collectCoverage",
|
"coverage": "jest --collectCoverage",
|
||||||
"coverage-html": "yarn run coverage && open ./coverage/index.html",
|
"coverage-html": "yarn run coverage && open ./coverage/index.html",
|
||||||
"codacy": "cat ./coverage/lcov.info | codacy-coverage",
|
"codacy": "cat ./coverage/lcov.info | codacy-coverage",
|
||||||
|
|
|
||||||
|
|
@ -22,13 +22,13 @@ rm -rf ${OUTPUT_DIR}
|
||||||
mkdir -p ${OUTPUT_DIR}
|
mkdir -p ${OUTPUT_DIR}
|
||||||
|
|
||||||
echo "Generating js aggregation file in ${OUTPUT_JS_FILE}"
|
echo "Generating js aggregation file in ${OUTPUT_JS_FILE}"
|
||||||
browserify -e ${INPUT_JS_FILE} -o ${OUTPUT_JS_FILE}
|
browserify -e ${INPUT_JS_FILE} -o ${OUTPUT_JS_FILE} -s global
|
||||||
|
|
||||||
echo "Minifying ${OUTPUT_JS_FILE} to ${OUTPUT_MIN_JS_FILE}"
|
echo "Minifying ${OUTPUT_JS_FILE} to ${OUTPUT_MIN_JS_FILE}"
|
||||||
terser ${OUTPUT_JS_FILE} -c -o ${OUTPUT_MIN_JS_FILE}
|
terser ${OUTPUT_JS_FILE} -c -o ${OUTPUT_MIN_JS_FILE}
|
||||||
|
|
||||||
echo "Generating js ui aggregation file in ${OUTPUT_JS_UI_FILE}"
|
echo "Generating js ui aggregation file in ${OUTPUT_JS_UI_FILE}"
|
||||||
browserify -e ${INPUT_JS_UI_FILE} -o ${OUTPUT_JS_UI_FILE}
|
browserify -e ${INPUT_JS_UI_FILE} -o ${OUTPUT_JS_UI_FILE} -s global
|
||||||
|
|
||||||
echo "Minifying ${OUTPUT_JS_UI_FILE} to ${OUTPUT_MIN_JS_UI_FILE}"
|
echo "Minifying ${OUTPUT_JS_UI_FILE} to ${OUTPUT_MIN_JS_UI_FILE}"
|
||||||
terser ${OUTPUT_JS_UI_FILE} -c -o ${OUTPUT_MIN_JS_UI_FILE}
|
terser ${OUTPUT_JS_UI_FILE} -c -o ${OUTPUT_MIN_JS_UI_FILE}
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,7 @@ type OptionsType = {
|
||||||
const templatesRoot = "website/templates";
|
const templatesRoot = "website/templates";
|
||||||
const pagesRoot = `${templatesRoot}/pages`;
|
const pagesRoot = `${templatesRoot}/pages`;
|
||||||
const options: OptionsType = {
|
const options: OptionsType = {
|
||||||
all: {
|
all: {},
|
||||||
demoUrl: "demo.html?diff=https://github.com/rtfpessoa/diff2html/pull/106"
|
|
||||||
},
|
|
||||||
demo: {
|
demo: {
|
||||||
extraClass: "template-index-min"
|
extraClass: "template-index-min"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,7 @@ function namespace(name: string): string {
|
||||||
// Write a template foreach file that matches template extension
|
// Write a template foreach file that matches template extension
|
||||||
const templates = extractFiles(options.argv.remain)
|
const templates = extractFiles(options.argv.remain)
|
||||||
.map(file => {
|
.map(file => {
|
||||||
const timmedFileContents = fs.readFileSync(file, "utf-8").trim();
|
const timmedFileContents = fs.readFileSync(file, "utf8").trim();
|
||||||
|
|
||||||
if (!timmedFileContents) return;
|
if (!timmedFileContents) return;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -415,7 +415,7 @@ describe("DiffParser", () => {
|
||||||
"+test2r\n"
|
"+test2r\n"
|
||||||
];
|
];
|
||||||
|
|
||||||
diffs.forEach(function(diff) {
|
diffs.forEach(diff => {
|
||||||
const result = parse(diff);
|
const result = parse(diff);
|
||||||
const file1 = result[0];
|
const file1 = result[0];
|
||||||
expect(result.length).toEqual(1);
|
expect(result.length).toEqual(1);
|
||||||
|
|
|
||||||
|
|
@ -256,32 +256,32 @@ describe("Diff2Html", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty line by line html from diff", () => {
|
it("should generate pretty line by line html from diff", () => {
|
||||||
const result = html(diffExample1);
|
const result = html(diffExample1, { drawFileList: false });
|
||||||
expect(result).toEqual(htmlLineExample1);
|
expect(result).toEqual(htmlLineExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty line by line html from json", () => {
|
it("should generate pretty line by line html from json", () => {
|
||||||
const result = html(jsonExample1);
|
const result = html(jsonExample1, { drawFileList: false });
|
||||||
expect(result).toEqual(htmlLineExample1);
|
expect(result).toEqual(htmlLineExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty diff with files summary", () => {
|
it("should generate pretty diff with files summary", () => {
|
||||||
const result = html(diffExample1, { showFiles: true });
|
const result = html(diffExample1, { drawFileList: true });
|
||||||
expect(result).toEqual(htmlLineExample1WithFilesSummary);
|
expect(result).toEqual(htmlLineExample1WithFilesSummary);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from diff", () => {
|
it("should generate pretty side by side html from diff", () => {
|
||||||
const result = html(diffExample1, { outputFormat: "side-by-side" });
|
const result = html(diffExample1, { outputFormat: "side-by-side", drawFileList: false });
|
||||||
expect(result).toEqual(htmlSideExample1);
|
expect(result).toEqual(htmlSideExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from json", () => {
|
it("should generate pretty side by side html from json", () => {
|
||||||
const result = html(jsonExample1, { outputFormat: "side-by-side" });
|
const result = html(jsonExample1, { outputFormat: "side-by-side", drawFileList: false });
|
||||||
expect(result).toEqual(htmlSideExample1);
|
expect(result).toEqual(htmlSideExample1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should generate pretty side by side html from diff 2", () => {
|
it("should generate pretty side by side html from diff 2", () => {
|
||||||
const result = html(diffExample1, { outputFormat: "side-by-side", showFiles: true });
|
const result = html(diffExample1, { outputFormat: "side-by-side", drawFileList: true });
|
||||||
expect(result).toEqual(htmlSideExample1WithFilesSummary);
|
expect(result).toEqual(htmlSideExample1WithFilesSummary);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -518,7 +518,7 @@ describe("Diff2Html", () => {
|
||||||
"</div>\n" +
|
"</div>\n" +
|
||||||
"</div>";
|
"</div>";
|
||||||
|
|
||||||
const result = html(diffExample2);
|
const result = html(diffExample2, { drawFileList: false });
|
||||||
expect(htmlExample2).toEqual(result);
|
expect(htmlExample2).toEqual(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -254,7 +254,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
diffLines.forEach(function(line, lineIndex) {
|
diffLines.forEach((line, lineIndex) => {
|
||||||
// Unmerged paths, and possibly other non-diffable files
|
// Unmerged paths, and possibly other non-diffable files
|
||||||
// https://github.com/scottgonzalez/pretty-diff/issues/11
|
// https://github.com/scottgonzalez/pretty-diff/issues/11
|
||||||
// Also, remove some useless lines
|
// Also, remove some useless lines
|
||||||
|
|
@ -340,8 +340,9 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(currentFile && line.startsWith(hunkHeaderPrefix)) ||
|
currentFile &&
|
||||||
(currentFile && currentFile.isGitDiff && currentFile.oldName && currentFile.newName && !currentBlock)
|
(line.startsWith(hunkHeaderPrefix) ||
|
||||||
|
(currentFile.isGitDiff && currentFile.oldName && currentFile.newName && !currentBlock))
|
||||||
) {
|
) {
|
||||||
startBlock(line);
|
startBlock(line);
|
||||||
return;
|
return;
|
||||||
|
|
@ -403,7 +404,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
||||||
currentFile.oldName = getFilename(values[1], undefined, config.srcPrefix);
|
currentFile.oldName = getFilename(values[1], undefined, config.srcPrefix);
|
||||||
currentFile.newName = getFilename(values[2], undefined, config.dstPrefix);
|
currentFile.newName = getFilename(values[2], undefined, config.dstPrefix);
|
||||||
startBlock("Binary file");
|
startBlock("Binary file");
|
||||||
} else if ((values = binaryDiff.exec(line))) {
|
} else if (binaryDiff.test(line)) {
|
||||||
currentFile.isBinary = true;
|
currentFile.isBinary = true;
|
||||||
startBlock(line);
|
startBlock(line);
|
||||||
} else if ((values = similarityIndex.exec(line))) {
|
} else if ((values = similarityIndex.exec(line))) {
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ export interface Diff2HtmlConfig
|
||||||
SideBySideRendererConfig,
|
SideBySideRendererConfig,
|
||||||
HoganJsUtilsConfig {
|
HoganJsUtilsConfig {
|
||||||
outputFormat?: OutputFormatType;
|
outputFormat?: OutputFormatType;
|
||||||
showFiles?: boolean;
|
drawFileList?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultDiff2HtmlConfig = {
|
export const defaultDiff2HtmlConfig = {
|
||||||
...defaultLineByLineRendererConfig,
|
...defaultLineByLineRendererConfig,
|
||||||
...defaultSideBySideRendererConfig,
|
...defaultSideBySideRendererConfig,
|
||||||
outputFormat: "line-by-line" as OutputFormatType,
|
outputFormat: "line-by-line" as OutputFormatType,
|
||||||
showFiles: false
|
drawFileList: true
|
||||||
};
|
};
|
||||||
|
|
||||||
export function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[] {
|
export function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[] {
|
||||||
|
|
@ -34,7 +34,7 @@ export function html(diffInput: string | DiffFile[], configuration: Diff2HtmlCon
|
||||||
|
|
||||||
const hoganUtils = new HoganJsUtils(config);
|
const hoganUtils = new HoganJsUtils(config);
|
||||||
|
|
||||||
const fileList = config.showFiles ? fileListPrinter.render(diffJson, hoganUtils) : "";
|
const fileList = config.drawFileList ? fileListPrinter.render(diffJson, hoganUtils) : "";
|
||||||
|
|
||||||
const diffOutput =
|
const diffOutput =
|
||||||
config.outputFormat === "side-by-side"
|
config.outputFormat === "side-by-side"
|
||||||
|
|
|
||||||
|
|
@ -10,10 +10,10 @@ export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const defaultLineByLineRendererConfig = {
|
export const defaultLineByLineRendererConfig = {
|
||||||
|
...renderUtils.defaultRenderConfig,
|
||||||
renderNothingWhenEmpty: false,
|
renderNothingWhenEmpty: false,
|
||||||
matchingMaxComparisons: 2500,
|
matchingMaxComparisons: 2500,
|
||||||
maxLineSizeInBlockForComparison: 200,
|
maxLineSizeInBlockForComparison: 200
|
||||||
...renderUtils.defaultRenderConfig
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const genericTemplatesPath = "generic";
|
const genericTemplatesPath = "generic";
|
||||||
|
|
|
||||||
|
|
@ -3,16 +3,24 @@ import * as HighlightJSInternals from "./highlight.js-internals";
|
||||||
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from "../../diff2html";
|
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from "../../diff2html";
|
||||||
import { DiffFile } from "../../render-utils";
|
import { DiffFile } from "../../render-utils";
|
||||||
|
|
||||||
interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
||||||
synchronisedScroll?: boolean;
|
synchronisedScroll?: boolean;
|
||||||
|
highlight?: boolean;
|
||||||
|
fileListToggle?: boolean;
|
||||||
|
fileListStartVisible?: boolean;
|
||||||
|
smartSelection?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultDiff2HtmlUIConfig = {
|
export const defaultDiff2HtmlUIConfig = {
|
||||||
...defaultDiff2HtmlConfig,
|
...defaultDiff2HtmlConfig,
|
||||||
synchronisedScroll: true
|
synchronisedScroll: true,
|
||||||
|
highlight: true,
|
||||||
|
fileListToggle: true,
|
||||||
|
fileListStartVisible: false,
|
||||||
|
smartSelection: true
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Diff2HtmlUI {
|
export class Diff2HtmlUI {
|
||||||
readonly config: typeof defaultDiff2HtmlUIConfig;
|
readonly config: typeof defaultDiff2HtmlUIConfig;
|
||||||
readonly diffHtml: string;
|
readonly diffHtml: string;
|
||||||
targetElement: HTMLElement;
|
targetElement: HTMLElement;
|
||||||
|
|
@ -26,32 +34,32 @@ export default class Diff2HtmlUI {
|
||||||
|
|
||||||
draw(): void {
|
draw(): void {
|
||||||
this.targetElement.innerHTML = this.diffHtml;
|
this.targetElement.innerHTML = this.diffHtml;
|
||||||
this.initSelection();
|
if (this.config.smartSelection) this.initSelection();
|
||||||
if (this.config.synchronisedScroll) this.synchronisedScroll();
|
if (this.config.synchronisedScroll) this.synchronisedScroll();
|
||||||
|
if (this.config.highlight) this.highlightCode();
|
||||||
|
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
synchronisedScroll(): void {
|
synchronisedScroll(): void {
|
||||||
this.targetElement.querySelectorAll(".d2h-file-wrapper").forEach(wrapper => {
|
this.targetElement.querySelectorAll(".d2h-file-wrapper").forEach(wrapper => {
|
||||||
const [left, right] = [].slice.call(wrapper.querySelectorAll(".d2h-file-side-diff")) as HTMLElement[];
|
const [left, right] = [].slice.call(wrapper.querySelectorAll(".d2h-file-side-diff")) as HTMLElement[];
|
||||||
|
|
||||||
if (left === undefined || right === undefined) return;
|
if (left === undefined || right === undefined) return;
|
||||||
|
|
||||||
const onScroll = (event: Event): void => {
|
const onScroll = (event: Event): void => {
|
||||||
if (event === null || event.target === null) return;
|
if (event === null || event.target === null) return;
|
||||||
|
|
||||||
if (event.target === left) {
|
if (event.target === left) {
|
||||||
right.scrollTop = left.scrollTop;
|
right.scrollTop = left.scrollTop;
|
||||||
|
right.scrollLeft = left.scrollLeft;
|
||||||
} else {
|
} else {
|
||||||
left.scrollTop = right.scrollTop;
|
left.scrollTop = right.scrollTop;
|
||||||
|
left.scrollLeft = right.scrollLeft;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
left.addEventListener("scroll", onScroll);
|
left.addEventListener("scroll", onScroll);
|
||||||
right.addEventListener("scroll", onScroll);
|
right.addEventListener("scroll", onScroll);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fileListCloseable(startVisible: boolean): void {
|
fileListToggle(startVisible: boolean): void {
|
||||||
const hashTag = this.getHashTag();
|
const hashTag = this.getHashTag();
|
||||||
|
|
||||||
const showBtn = this.targetElement.querySelector(".d2h-show") as HTMLElement;
|
const showBtn = this.targetElement.querySelector(".d2h-show") as HTMLElement;
|
||||||
|
|
@ -61,13 +69,13 @@ export default class Diff2HtmlUI {
|
||||||
if (showBtn === null || hideBtn === null || fileList === null) return;
|
if (showBtn === null || hideBtn === null || fileList === null) return;
|
||||||
|
|
||||||
function show(): void {
|
function show(): void {
|
||||||
showBtn.style.display = "";
|
showBtn.style.display = "none";
|
||||||
hideBtn.style.display = "";
|
hideBtn.style.display = "inline";
|
||||||
fileList.style.display = "";
|
fileList.style.display = "block";
|
||||||
}
|
}
|
||||||
|
|
||||||
function hide(): void {
|
function hide(): void {
|
||||||
showBtn.style.display = "none";
|
showBtn.style.display = "inline";
|
||||||
hideBtn.style.display = "none";
|
hideBtn.style.display = "none";
|
||||||
fileList.style.display = "none";
|
fileList.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
@ -204,7 +212,7 @@ export default class Diff2HtmlUI {
|
||||||
nodes.forEach((tr, i) => {
|
nodes.forEach((tr, i) => {
|
||||||
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
|
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
|
||||||
|
|
||||||
if (td === null || td.textContent === null) return;
|
if (td === undefined || td.textContent === null) return;
|
||||||
|
|
||||||
text += (i ? "\n" : "") + td.textContent.replace(/(?:\r\n|\r|\n)/g, "");
|
text += (i ? "\n" : "") + td.textContent.replace(/(?:\r\n|\r|\n)/g, "");
|
||||||
});
|
});
|
||||||
|
|
@ -213,8 +221,3 @@ export default class Diff2HtmlUI {
|
||||||
return text;
|
return text;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Avoid disabling types
|
|
||||||
// eslint-disable-next-line
|
|
||||||
// @ts-ignore
|
|
||||||
global.Diff2HtmlUI = Diff2HtmlUI;
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ export function escapeForHtml(str: string): string {
|
||||||
* Converts all '\' in @path to unix style '/'
|
* Converts all '\' in @path to unix style '/'
|
||||||
*/
|
*/
|
||||||
export function unifyPath(path: string): string {
|
export function unifyPath(path: string): string {
|
||||||
return path ? path.replace("\\", "/") : path;
|
return path ? path.replace(/\\/g, "/") : path;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
/* global Diff2HtmlUI */
|
/* global global */
|
||||||
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
@ -16,33 +16,33 @@
|
||||||
|
|
||||||
const searchParam = "diff";
|
const searchParam = "diff";
|
||||||
|
|
||||||
function getUrlFromSearch(search) {
|
|
||||||
try {
|
|
||||||
return search
|
|
||||||
.split("?")[1]
|
|
||||||
.split(searchParam + "=")[1]
|
|
||||||
.split("&")[0];
|
|
||||||
} catch (_ignore) {}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getParamsFromSearch(search) {
|
function getParamsFromSearch(search) {
|
||||||
const map = new Map();
|
const map = {};
|
||||||
try {
|
try {
|
||||||
search
|
search
|
||||||
.split("?")[1]
|
.split("?")[1]
|
||||||
.split("&")
|
.split("&")
|
||||||
.forEach(e => {
|
.forEach(e => {
|
||||||
const values = e.split("=");
|
const values = e.split("=");
|
||||||
map.set(values[0], values[1]);
|
map[values[0]] = values[1];
|
||||||
});
|
});
|
||||||
} catch (_ignore) {}
|
} catch (_ignore) {}
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
function prepareUrl(url) {
|
function validateUrl(url) {
|
||||||
|
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
|
||||||
|
url
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function prepareRequest(url) {
|
||||||
|
if (!validateUrl(url)) {
|
||||||
|
console.error("Invalid url provided!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let fetchUrl;
|
let fetchUrl;
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
|
|
||||||
|
|
@ -93,150 +93,152 @@ function prepareUrl(url) {
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
originalUrl: url,
|
|
||||||
url: fetchUrl,
|
url: fetchUrl,
|
||||||
headers: headers
|
headers: headers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function validateUrl(url) {
|
function getConfiguration(urlParams) {
|
||||||
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
|
// Removing `diff` form `urlParams` to avoid being inserted
|
||||||
url
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
);
|
const { diff, ...urlParamsRest } = urlParams;
|
||||||
|
const config = {
|
||||||
|
...global.defaultDiff2HtmlUIConfig,
|
||||||
|
...urlParamsRest
|
||||||
|
};
|
||||||
|
|
||||||
|
return Object.entries(config).reduce((object, [k, v]) => {
|
||||||
|
const newObject = !Number.isNaN(Number(v))
|
||||||
|
? { [k]: Number(v) }
|
||||||
|
: v === "true" && v === "false"
|
||||||
|
? { [k]: Boolean(v) }
|
||||||
|
: { [k]: v };
|
||||||
|
return { ...object, ...newObject };
|
||||||
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateUrl(url) {
|
function getDiff(request) {
|
||||||
const params = getParamsFromSearch(window.location.search);
|
return fetch(request.url, {
|
||||||
|
|
||||||
if (params[searchParam] === url) return;
|
|
||||||
|
|
||||||
params[searchParam] = url;
|
|
||||||
|
|
||||||
const paramString = Object.keys(params)
|
|
||||||
.map(function(k) {
|
|
||||||
return k + "=" + params[k];
|
|
||||||
})
|
|
||||||
.join("&");
|
|
||||||
|
|
||||||
window.location = "demo.html?" + paramString;
|
|
||||||
}
|
|
||||||
|
|
||||||
function draw(req, forced, elements) {
|
|
||||||
if (!validateUrl(req.url)) {
|
|
||||||
console.error("Invalid url provided!");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (validateUrl(req.originalUrl)) updateUrl(req.originalUrl);
|
|
||||||
|
|
||||||
const outputFormat = elements.outputFormat.val();
|
|
||||||
const showFiles = elements.showFiles.is(":checked");
|
|
||||||
const matching = elements.matching.val();
|
|
||||||
const wordsThreshold = elements.wordsThreshold.val();
|
|
||||||
const matchingMaxComparisons = elements.matchingMaxComparisons.val();
|
|
||||||
|
|
||||||
fetch(req.url, {
|
|
||||||
method: "GET",
|
method: "GET",
|
||||||
headers: req.headers,
|
headers: request.headers,
|
||||||
mode: "cors",
|
mode: "cors",
|
||||||
cache: "default"
|
cache: "default"
|
||||||
})
|
})
|
||||||
.then(function(res) {
|
.then(res => {
|
||||||
return res.text();
|
return res.text();
|
||||||
})
|
})
|
||||||
.then(function(data) {
|
.catch(error => console.error("Failed to retrieve diff", error));
|
||||||
const params = getParamsFromSearch(window.location.search);
|
}
|
||||||
delete params[searchParam];
|
|
||||||
|
|
||||||
if (forced) {
|
function draw(diffString, config, elements) {
|
||||||
params.outputFormat = outputFormat;
|
const diff2htmlUi = new global.Diff2HtmlUI(diffString, elements.structure.diffTarget, config);
|
||||||
params.showFiles = showFiles;
|
|
||||||
params.matching = matching;
|
if (config.outputFormat === "side-by-side") {
|
||||||
params.wordsThreshold = wordsThreshold;
|
elements.structure.container.style.width = "100%";
|
||||||
params.matchingMaxComparisons = matchingMaxComparisons;
|
|
||||||
} else {
|
} else {
|
||||||
params.outputFormat = params.outputFormat || outputFormat;
|
elements.structure.container.style.width = "";
|
||||||
params.showFiles = String(params.showFiles) !== "false" || (params.showFiles === null && showFiles);
|
|
||||||
params.matching = params.matching || matching;
|
|
||||||
params.wordsThreshold = params.wordsThreshold || wordsThreshold;
|
|
||||||
params.matchingMaxComparisons = params.matchingMaxComparisons || matchingMaxComparisons;
|
|
||||||
|
|
||||||
elements.outputFormat.value = params.outputFormat;
|
|
||||||
elements.showFiles.setAttribute("checked", params.showFiles);
|
|
||||||
elements.matching.value = params.matching;
|
|
||||||
elements.wordsThreshold.value = params.wordsThreshold;
|
|
||||||
elements.matchingMaxComparisons.value = params.matchingMaxComparisons;
|
|
||||||
}
|
|
||||||
|
|
||||||
params.synchronisedScroll = params.synchronisedScroll || true;
|
|
||||||
|
|
||||||
const diff2htmlUi = new Diff2HtmlUI(data, elements.root);
|
|
||||||
|
|
||||||
if (outputFormat === "side-by-side") {
|
|
||||||
elements.container.css({ width: "100%" });
|
|
||||||
} else {
|
|
||||||
elements.container.css({ width: "" });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
diff2htmlUi.draw();
|
diff2htmlUi.draw();
|
||||||
diff2htmlUi.fileListCloseable(params.fileListCloseable || false);
|
}
|
||||||
if (params.highlight === undefined || params.highlight) {
|
|
||||||
diff2htmlUi.highlightCode();
|
async function prepareInitialState(elements) {
|
||||||
|
const urlParams = getParamsFromSearch(window.location.search);
|
||||||
|
const currentUrl = (urlParams && urlParams[searchParam]) || "https://github.com/rtfpessoa/diff2html/pull/106";
|
||||||
|
|
||||||
|
if (currentUrl !== elements.url.input.value) elements.url.input.value = currentUrl;
|
||||||
|
|
||||||
|
const request = prepareRequest(currentUrl);
|
||||||
|
|
||||||
|
const initialConfiguration = getConfiguration(urlParams);
|
||||||
|
const initialDiff = await getDiff(request);
|
||||||
|
|
||||||
|
return [initialConfiguration, initialDiff];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateBrowserUrl(config, newDiffUrl) {
|
||||||
|
if (history.pushState) {
|
||||||
|
const paramString = Object.entries(config)
|
||||||
|
.map(([k, v]) => k + "=" + v)
|
||||||
|
.join("&");
|
||||||
|
const newPageUrl =
|
||||||
|
window.location.protocol +
|
||||||
|
"//" +
|
||||||
|
window.location.host +
|
||||||
|
window.location.pathname +
|
||||||
|
"?" +
|
||||||
|
paramString +
|
||||||
|
"&" +
|
||||||
|
searchParam +
|
||||||
|
"=" +
|
||||||
|
newDiffUrl;
|
||||||
|
window.history.pushState({ path: newPageUrl }, "", newPageUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
|
||||||
})
|
|
||||||
.catch(() => {});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function smartDraw(urlOpt, urlElem, forced) {
|
document.addEventListener("DOMContentLoaded", async () => {
|
||||||
const url = urlOpt || urlElem.val();
|
|
||||||
const req = prepareUrl(url);
|
|
||||||
draw(req, forced);
|
|
||||||
}
|
|
||||||
|
|
||||||
function bind(urlElem) {
|
|
||||||
$("#url-btn").click(e => {
|
|
||||||
e.preventDefault();
|
|
||||||
const url = urlElem.val();
|
|
||||||
smartDraw(url, urlElem);
|
|
||||||
});
|
|
||||||
|
|
||||||
urlElem.on("paste", e => {
|
|
||||||
const url = e.originalEvent.clipboardData.getData("Text");
|
|
||||||
smartDraw(url, urlElem);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
document.addEventListener("DOMContentLoaded", function() {
|
|
||||||
// Improves browser compatibility
|
// Improves browser compatibility
|
||||||
require("whatwg-fetch");
|
require("whatwg-fetch");
|
||||||
|
|
||||||
|
const drawAndUpdateUrl = async (diffUrl, diffString, config, elements) => {
|
||||||
|
updateBrowserUrl(config, diffUrl);
|
||||||
|
const newRequest = prepareRequest(diffUrl);
|
||||||
|
diffString = await getDiff(newRequest);
|
||||||
|
draw(diffString, config, elements);
|
||||||
|
};
|
||||||
|
|
||||||
const elements = {
|
const elements = {
|
||||||
root: document.getElementById("url-diff-container"),
|
structure: {
|
||||||
container: document.getElementsByClassName("container"),
|
container: document.getElementsByClassName("container")[0],
|
||||||
url: document.getElementById("url"),
|
diffTarget: document.getElementById("url-diff-container")
|
||||||
|
},
|
||||||
|
url: {
|
||||||
|
input: document.getElementById("url"),
|
||||||
|
button: document.getElementById("url-btn")
|
||||||
|
},
|
||||||
|
options: {
|
||||||
outputFormat: document.getElementById("diff-url-options-output-format"),
|
outputFormat: document.getElementById("diff-url-options-output-format"),
|
||||||
showFiles: document.getElementById("diff-url-options-show-files"),
|
|
||||||
matching: document.getElementById("diff-url-options-matching"),
|
matching: document.getElementById("diff-url-options-matching"),
|
||||||
wordsThreshold: document.getElementById("diff-url-options-match-words-threshold"),
|
wordsThreshold: document.getElementById("diff-url-options-match-words-threshold"),
|
||||||
matchingMaxComparisons: document.getElementById("diff-url-options-matching-max-comparisons")
|
matchingMaxComparisons: document.getElementById("diff-url-options-matching-max-comparisons")
|
||||||
|
},
|
||||||
|
checkboxes: {
|
||||||
|
drawFileList: document.getElementById("diff-url-options-show-files")
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (window.location.search) {
|
let [config, diffString] = await prepareInitialState(elements);
|
||||||
const url = getUrlFromSearch(window.location.search);
|
|
||||||
elements.url.val(url);
|
|
||||||
smartDraw(url, elements.url);
|
|
||||||
}
|
|
||||||
|
|
||||||
bind();
|
// Update HTML inputs from any changes in URL
|
||||||
|
elements.options.outputFormat.value = config.outputFormat;
|
||||||
|
elements.checkboxes.drawFileList.checked = config.drawFileList;
|
||||||
|
elements.options.matching.value = config.matching;
|
||||||
|
elements.options.wordsThreshold.value = config.wordsThreshold;
|
||||||
|
elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons;
|
||||||
|
|
||||||
elements.outputFormat
|
Object.entries(elements.options).forEach(([option, element]) =>
|
||||||
.add(elements.showFiles)
|
element.addEventListener("change", () => {
|
||||||
.add(elements.matching)
|
config[option] = element.value;
|
||||||
.add(elements.wordsThreshold)
|
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
||||||
.add(elements.matchingMaxComparisons)
|
})
|
||||||
.change(() => smartDraw(null, elements.url, true));
|
);
|
||||||
|
|
||||||
|
Object.entries(elements.checkboxes).forEach(([option, checkbox]) =>
|
||||||
|
checkbox.addEventListener("change", () => {
|
||||||
|
config[option] = checkbox.checked;
|
||||||
|
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
elements.url.button.addEventListener("click", async e => {
|
||||||
|
e.preventDefault();
|
||||||
|
const newDiffUrl = elements.url.input.value;
|
||||||
|
const newRequest = prepareRequest(newDiffUrl);
|
||||||
|
diffString = await getDiff(newRequest);
|
||||||
|
drawAndUpdateUrl(newDiffUrl, diffString, config, elements);
|
||||||
|
});
|
||||||
|
|
||||||
|
return drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
||||||
});
|
});
|
||||||
|
|
||||||
/* eslint-enable @typescript-eslint/explicit-function-return-type */
|
/* eslint-enable @typescript-eslint/explicit-function-return-type */
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
</div>
|
</div>
|
||||||
<div class=" col-md-2 col-xs-12 col-15">
|
<div class=" col-md-2 col-xs-12 col-15">
|
||||||
<label title="Show the file list summary before the diff">File Summary
|
<label title="Show the file list summary before the diff">File Summary
|
||||||
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="showFiles" checked/>
|
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList" checked/>
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class=" col-md-2 col-xs-12 col-15">
|
<div class=" col-md-2 col-xs-12 col-15">
|
||||||
|
|
@ -78,7 +78,7 @@
|
||||||
<b>Can I send a custom url for a friend, colleague or co-worker?</b>
|
<b>Can I send a custom url for a friend, colleague or co-worker?</b>
|
||||||
<p>Just add a url parameter called diff to current url using as value your Commit, Pull Request, Merge Request, Diff
|
<p>Just add a url parameter called diff to current url using as value your Commit, Pull Request, Merge Request, Diff
|
||||||
or Patch url.</p>
|
or Patch url.</p>
|
||||||
<p>ex: <a href="{{ demoUrl }}">https://diff2html.xyz/{{ demoUrl }}</a>
|
<p>ex: <a href="demo.html">https://diff2html.xyz/demo.html</a>
|
||||||
</p>
|
</p>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,17 @@
|
||||||
</span>
|
</span>
|
||||||
<h1 class="hero-header">Diff parser and pretty html generator</h1>
|
<h1 class="hero-header">Diff parser and pretty html generator</h1>
|
||||||
<h4 class="text-muted">Better diffs, unmatched reviews.</h4>
|
<h4 class="text-muted">Better diffs, unmatched reviews.</h4>
|
||||||
<h2><a class="btn btn-lg" href="{{ demoUrl }}">Demo</a></h2>
|
<h2><a class="btn btn-lg" href="demo.html">Demo</a></h2>
|
||||||
|
|
||||||
<div class="screenshots screenshots-fan clearfix">
|
<div class="screenshots screenshots-fan clearfix">
|
||||||
|
|
||||||
<img class="screenshot hidden-xs" src="img/snapshot-2.png">
|
<img class="screenshot hidden-xs" src="img/snapshot-2.png">
|
||||||
|
|
||||||
<a class="screenshot" href="{{ demoUrl }}">
|
<a class="screenshot" href="demo.html">
|
||||||
<img src="img/snapshot-3.png">
|
<img src="img/snapshot-3.png">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<a class="screenshot hidden-xs" href="{{ demoUrl }}">
|
<a class="screenshot hidden-xs" href="demo.html">
|
||||||
<img src="img/snapshot-1.png">
|
<img src="img/snapshot-1.png">
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,6 @@
|
||||||
|
|
||||||
ga('create', 'UA-78351861-2', 'auto');
|
ga('create', 'UA-78351861-2', 'auto');
|
||||||
ga('send', 'pageview');
|
ga('send', 'pageview');
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="template-index {{extraClass}}">
|
<body class="template-index {{extraClass}}">
|
||||||
|
|
@ -76,7 +75,7 @@
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
<a href="{{ demoUrl }}">Demo</a>
|
<a href="demo.html">Demo</a>
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li>
|
<li>
|
||||||
|
|
@ -121,11 +120,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- General JavaScript -->
|
<!-- General JavaScript -->
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
|
|
||||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"
|
|
||||||
integrity="sha384-0mSbJDEHialfmuBBQP6A4Qrprq5OVfW37PRR3j5ELqxss1yVqOtnepnHVP9aJ7xS"
|
|
||||||
crossorigin="anonymous"></script>
|
|
||||||
|
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{
|
||||||
"@context": "http://schema.org/",
|
"@context": "http://schema.org/",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue