wip: tweaks to website

This commit is contained in:
Rodrigo Fernandes 2019-10-13 19:21:19 +01:00
parent 4f607633dd
commit f72ee2ea46
No known key found for this signature in database
GPG key ID: 67157D2E3D4258B4
18 changed files with 315 additions and 330 deletions

View file

@ -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

View file

@ -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
View file

@ -1,9 +1,8 @@
# diff2html # diff2html
[![Codacy Quality Badge](https://api.codacy.com/project/badge/Grade/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=rtfpessoa/diff2html&amp;utm_campaign=Badge_Grade) [![Codacy Quality Badge](https://api.codacy.com/project/badge/Grade/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
[![Codacy Coverage Badge](https://api.codacy.com/project/badge/Coverage/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage) [![Codacy Coverage Badge](https://api.codacy.com/project/badge/Coverage/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
[![Circle CI](https://circleci.com/gh/rtfpessoa/diff2html.svg?style=svg)](https://circleci.com/gh/rtfpessoa/diff2html) [![Circle CI](https://circleci.com/gh/rtfpessoa/diff2html.svg?style=svg)](https://circleci.com/gh/rtfpessoa/diff2html)
[![Dependency Status](https://dependencyci.com/github/rtfpessoa/diff2html/badge)](https://dependencyci.com/github/rtfpessoa/diff2html)
[![npm](https://img.shields.io/npm/v/diff2html.svg)](https://www.npmjs.com/package/diff2html) [![npm](https://img.shields.io/npm/v/diff2html.svg)](https://www.npmjs.com/package/diff2html)
[![Dependency Status](https://david-dm.org/rtfpessoa/diff2html.svg)](https://david-dm.org/rtfpessoa/diff2html) [![Dependency Status](https://david-dm.org/rtfpessoa/diff2html.svg)](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!

View file

@ -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",

View file

@ -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}

View 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"
} }

View file

@ -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;

View file

@ -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);

View file

@ -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);
}); });
}); });

View file

@ -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))) {

View file

@ -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"

View file

@ -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";

View file

@ -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;

View file

@ -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;
} }
/** /**

View file

@ -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 */

View file

@ -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>

View file

@ -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>

View file

@ -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/",