diff --git a/README.md b/README.md index 4348ac1..bd92a31 100644 --- a/README.md +++ b/README.md @@ -32,29 +32,25 @@ Diff to Html generates pretty HTML diffs from git diff output. ## How to use -> Pretty Line-by-Line Html From Git Word Diff Output +> Pretty HTML diff - Diff2Html.getPrettyHtmlFromDiff(exInput) - -> Pretty Side-by-Side Html From Git Word Diff Output - - Diff2Html.getPrettySideBySideHtmlFromDiff(exInput) + Diff2Html.getPrettyHtml(exInput, configuration) > Intermediate Json From Git Word Diff Output Diff2Html.getJsonFromDiff(exInput) -> Pretty Line-by-Line Html From Json - - Diff2Html.getPrettyHtmlFromJson(exInput) - -> Pretty Side-by-Side Html From Json - - Diff2Html.getPrettySideBySideHtmlFromJson(exInput) - > Check out the `index.html` for a complete example. -## Sintax Hightlight +## Configuration +The HTML output accepts a Javascript object with configuration. Possible options: + + - `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'` + - `showFiles`: show a file list before the diff: `true` or `false`, default is `false` + + +## Syntax Highlight > Add the dependencies. Choose one color scheme, and add the main highlight code. @@ -90,8 +86,8 @@ document.addEventListener("DOMContentLoaded", function () { hljs.configure({languages: distinctLanguages}); // generate and inject the diff HTML into the desired place - document.getElementById("line-by-line").innerHTML = Diff2Html.getPrettyHtmlFromJson(diffJson); - document.getElementById("side-by-side").innerHTML = Diff2Html.getPrettySideBySideHtmlFromJson(diffJson); + document.getElementById("line-by-line").innerHTML = Diff2Html.getPrettyHtml(diffJson, { inputFormat: 'json' }); + document.getElementById("side-by-side").innerHTML = Diff2Html.getPrettyHtml(diffJson, { inputFormat: 'json', outputFormat: 'side-by-side' }); // collect all the code lines and execute the highlight on them var codeLines = document.getElementsByClassName("d2h-code-line-ctn"); diff --git a/css/diff2html.css b/css/diff2html.css index df448ba..fc4b5f8 100644 --- a/css/diff2html.css +++ b/css/diff2html.css @@ -207,3 +207,61 @@ color: rgba(0, 0, 0, 0.3); border-color: #d5e4f2; } + +.d2h-file-list-wrapper { + margin-bottom: 10px; + padding: 0 10px; +} + +.d2h-file-list-wrapper a { + text-decoration: none; + color: #3572b0; +} + +.d2h-file-list-wrapper a:visited { + color: #3572b0; +} + +.d2h-file-list-header { + font-weight: bold; + margin-bottom: 5px; + text-align: left; + display: inline; + float:left; +} + +.d2h-file-list-line { + text-align: left; + font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; +} + +.d2h-file-list-line .d2h-file-name { + line-height: 21px; +} + +.d2h-file-list { + display:none; +} + +.d2h-clear { + display:block; + clear: both; +} + +/* CSS only show/hide */ +.d2h-show { + display: none; + float:left; +} +.d2h-hide { + float:left; +} +.d2h-hide:target + .d2h-show { + display: inline; +} +.d2h-hide:target { + display: none; +} +.d2h-hide:target ~ .d2h-file-list { + display:block; +} diff --git a/dist/diff2html.css b/dist/diff2html.css index df448ba..fc4b5f8 100644 --- a/dist/diff2html.css +++ b/dist/diff2html.css @@ -207,3 +207,61 @@ color: rgba(0, 0, 0, 0.3); border-color: #d5e4f2; } + +.d2h-file-list-wrapper { + margin-bottom: 10px; + padding: 0 10px; +} + +.d2h-file-list-wrapper a { + text-decoration: none; + color: #3572b0; +} + +.d2h-file-list-wrapper a:visited { + color: #3572b0; +} + +.d2h-file-list-header { + font-weight: bold; + margin-bottom: 5px; + text-align: left; + display: inline; + float:left; +} + +.d2h-file-list-line { + text-align: left; + font: 13px Helvetica, arial, freesans, clean, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol"; +} + +.d2h-file-list-line .d2h-file-name { + line-height: 21px; +} + +.d2h-file-list { + display:none; +} + +.d2h-clear { + display:block; + clear: both; +} + +/* CSS only show/hide */ +.d2h-show { + display: none; + float:left; +} +.d2h-hide { + float:left; +} +.d2h-hide:target + .d2h-show { + display: inline; +} +.d2h-hide:target { + display: none; +} +.d2h-hide:target ~ .d2h-file-list { + display:block; +} diff --git a/dist/diff2html.js b/dist/diff2html.js index 80c191d..1d17685 100644 --- a/dist/diff2html.js +++ b/dist/diff2html.js @@ -54,7 +54,8 @@ (function(ctx, undefined) { var diffParser = __webpack_require__(1).DiffParser; - var htmlPrinter = __webpack_require__(3).HtmlPrinter; + var fileLister = __webpack_require__(3).FileListPrinter; + var htmlPrinter = __webpack_require__(6).HtmlPrinter; function Diff2Html() { } @@ -68,15 +69,6 @@ }; */ - /* - * Generates pretty html from string diff input - */ - Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) { - var diffJson = diffParser.generateDiffJson(diffInput); - var configOrEmpty = config || {}; - return htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); - }; - /* * Generates json object from string diff input */ @@ -84,22 +76,65 @@ return diffParser.generateDiffJson(diffInput); }; + /* + * Generates the html diff. The config parameter configures the output/input formats and other options + */ + Diff2Html.prototype.getPrettyHtml = function(diffInput, config) { + var configOrEmpty = config || {}; + + var diffJson = diffInput; + if(!configOrEmpty.inputFormat || configOrEmpty.inputFormat === 'diff') { + diffJson = diffParser.generateDiffJson(diffInput); + } + + var fileList = ""; + if(configOrEmpty.showFiles === true) { + fileList = fileLister.generateFileList(diffJson, configOrEmpty); + } + + var diffOutput = ""; + if(configOrEmpty.outputFormat === 'side-by-side') { + diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + } else { + diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); + } + + return fileList + diffOutput + }; + + + /* + * Deprecated methods - The following methods exist only to maintain compatibility with previous versions + */ + + /* + * Generates pretty html from string diff input + */ + Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) { + var configOrEmpty = config || {}; + configOrEmpty['inputFormat'] = 'diff'; + configOrEmpty['outputFormat'] = 'line-by-line'; + return this.getPrettyHtml(diffInput, configOrEmpty) + }; + /* * Generates pretty html from a json object */ Diff2Html.prototype.getPrettyHtmlFromJson = function(diffJson, config) { var configOrEmpty = config || {}; - return htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'json'; + configOrEmpty['outputFormat'] = 'line-by-line'; + return this.getPrettyHtml(diffJson, configOrEmpty) }; /* * Generates pretty side by side html from string diff input */ Diff2Html.prototype.getPrettySideBySideHtmlFromDiff = function(diffInput, config) { - var diffJson = diffParser.generateDiffJson(diffInput); - var configOrEmpty = config || {}; - return htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'diff'; + configOrEmpty['outputFormat'] = 'side-by-side'; + return this.getPrettyHtml(diffInput, configOrEmpty) }; /* @@ -107,7 +142,9 @@ */ Diff2Html.prototype.getPrettySideBySideHtmlFromJson = function(diffJson, config) { var configOrEmpty = config || {}; - return htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'json'; + configOrEmpty['outputFormat'] = 'side-by-side'; + return this.getPrettyHtml(diffJson, configOrEmpty) }; var diffName = 'Diff2Html'; @@ -373,6 +410,10 @@ .replace(/\t/g, ' '); }; + Utils.prototype.getRandomId = function(prefix) { + return prefix + "-" + Math.random().toString(36).slice(-3); + }; + Utils.prototype.startsWith = function(str, start) { if (typeof start === 'object') { var result = false; @@ -403,204 +444,49 @@ /* * - * HtmlPrinter (html-printer.js) - * Author: rtfpessoa + * FileListPrinter (file-list-printer.js) + * Author: nmatpt * */ - (function(ctx, undefined) { + (function (ctx, undefined) { - var lineByLinePrinter = __webpack_require__(4).LineByLinePrinter; - var sideBySidePrinter = __webpack_require__(7).SideBySidePrinter; + var printerUtils = __webpack_require__(4).PrinterUtils; + var utils = __webpack_require__(2).Utils; - function HtmlPrinter() { - } + function FileListPrinter() { + } - HtmlPrinter.prototype.generateLineByLineJsonHtml = lineByLinePrinter.generateLineByLineJsonHtml; + FileListPrinter.prototype.generateFileList = function (diffFiles) { + var hideId = utils.getRandomId("d2h-hide"); + var showId = utils.getRandomId("d2h-show"); + return '
\n' + + '
Files changed (' + diffFiles.length + ')  
\n' + + ' +\n' + + ' -\n' + + '
\n' + + '
\n' + - HtmlPrinter.prototype.generateSideBySideJsonHtml = sideBySidePrinter.generateSideBySideJsonHtml; - module.exports['HtmlPrinter'] = new HtmlPrinter(); + diffFiles.map(function (file) { + return '
\n' + + '
\n' + + ' +' + file.addedLines + '\n' + + ' -' + file.deletedLines + '\n' + + '
\n' + + ' \n' + + '
\n' + }).join('\n') + + '
\n'; + }; + + module.exports['FileListPrinter'] = new FileListPrinter(); })(this); /***/ }, /* 4 */ -/***/ function(module, exports, __webpack_require__) { - - /* - * - * LineByLinePrinter (line-by-line-printer.js) - * Author: rtfpessoa - * - */ - - (function(ctx, undefined) { - - var diffParser = __webpack_require__(1).DiffParser; - var printerUtils = __webpack_require__(5).PrinterUtils; - var utils = __webpack_require__(2).Utils; - - function LineByLinePrinter() { - } - - LineByLinePrinter.prototype.generateLineByLineJsonHtml = function(diffFiles, config) { - return '
\n' + - diffFiles.map(function(file) { - - var diffs; - if (file.blocks.length) { - diffs = generateFileHtml(file, config); - } else { - diffs = generateEmptyDiff(); - } - - return '
\n' + - '
\n' + - '
\n' + - ' +' + file.addedLines + '\n' + - ' -' + file.deletedLines + '\n' + - '
\n' + - '
' + printerUtils.getDiffName(file) + '
\n' + - '
\n' + - '
\n' + - '
\n' + - ' \n' + - ' \n' + - ' ' + diffs + - ' \n' + - '
\n' + - '
\n' + - '
\n' + - '
\n'; - }).join('\n') + - '
\n'; - }; - - function generateFileHtml(file, config) { - return file.blocks.map(function(block) { - - var lines = '\n' + - ' \n' + - ' ' + - '
' + utils.escape(block.header) + '
' + - ' \n' + - '\n'; - - var oldLines = []; - var newLines = []; - var processedOldLines = []; - var processedNewLines = []; - - for (var i = 0; i < block.lines.length; i++) { - var line = block.lines[i]; - var escapedLine = utils.escape(line.content); - - if (line.type == diffParser.LINE_TYPE.CONTEXT && !oldLines.length && !newLines.length) { - lines += generateLineHtml(line.type, line.oldNumber, line.newNumber, escapedLine); - } else if (line.type == diffParser.LINE_TYPE.INSERTS && !oldLines.length && !newLines.length) { - lines += generateLineHtml(line.type, line.oldNumber, line.newNumber, escapedLine); - } else if (line.type == diffParser.LINE_TYPE.DELETES && !newLines.length) { - oldLines.push(line); - } else if (line.type == diffParser.LINE_TYPE.INSERTS && oldLines.length > newLines.length) { - newLines.push(line); - } else { - var j = 0; - var oldLine, newLine; - - if (oldLines.length === newLines.length) { - for (j = 0; j < oldLines.length; j++) { - oldLine = oldLines[j]; - newLine = newLines[j]; - - config.isCombined = file.isCombined; - var diff = printerUtils.diffHighlight(oldLine.content, newLine.content, config); - - processedOldLines += - generateLineHtml(oldLine.type, oldLine.oldNumber, oldLine.newNumber, - diff.first.line, diff.first.prefix); - processedNewLines += - generateLineHtml(newLine.type, newLine.oldNumber, newLine.newNumber, - diff.second.line, diff.second.prefix); - } - - lines += processedOldLines + processedNewLines; - } else { - lines += processLines(oldLines, newLines); - } - - oldLines = []; - newLines = []; - processedOldLines = []; - processedNewLines = []; - i--; - } - } - - lines += processLines(oldLines, newLines); - - return lines; - }).join('\n'); - } - - function processLines(oldLines, newLines) { - var lines = ''; - - for (j = 0; j < oldLines.length; j++) { - var oldLine = oldLines[j]; - var oldEscapedLine = utils.escape(oldLine.content); - lines += generateLineHtml(oldLine.type, oldLine.oldNumber, oldLine.newNumber, oldEscapedLine); - } - - for (j = 0; j < newLines.length; j++) { - var newLine = newLines[j]; - var newEscapedLine = utils.escape(newLine.content); - lines += generateLineHtml(newLine.type, newLine.oldNumber, newLine.newNumber, newEscapedLine); - } - - return lines; - } - - function generateLineHtml(type, oldNumber, newNumber, content, prefix) { - var htmlPrefix = ''; - if (prefix) { - htmlPrefix = '' + prefix + ''; - } - - var htmlContent = ''; - if (content) { - htmlContent = '' + content + ''; - } - - return '\n' + - ' ' + - '
' + utils.valueOrEmpty(oldNumber) + '
' + - '
' + utils.valueOrEmpty(newNumber) + '
' + - ' \n' + - ' ' + - '
' + htmlPrefix + htmlContent + '
' + - ' \n' + - '\n'; - } - - function generateEmptyDiff() { - return '\n' + - ' ' + - '
' + - 'File without changes' + - '
' + - ' \n' + - '\n'; - } - - module.exports['LineByLinePrinter'] = new LineByLinePrinter(); - - })(this); - - -/***/ }, -/* 5 */ /***/ function(module, exports, __webpack_require__) { /* @@ -612,12 +498,16 @@ (function(ctx, undefined) { - var jsDiff = __webpack_require__(6); + var jsDiff = __webpack_require__(5); var utils = __webpack_require__(2).Utils; function PrinterUtils() { } + PrinterUtils.prototype.getHtmlId = function(file) { + return "d2h-" + this.getDiffName(file); + }; + PrinterUtils.prototype.getDiffName = function(file) { var oldFilename = file.oldName; var newFilename = file.newName; @@ -700,7 +590,7 @@ /***/ }, -/* 6 */ +/* 5 */ /***/ function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/* See LICENSE file for terms of use */ @@ -1324,8 +1214,210 @@ }(this)); +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + /* + * + * HtmlPrinter (html-printer.js) + * Author: rtfpessoa + * + */ + + (function(ctx, undefined) { + + var lineByLinePrinter = __webpack_require__(7).LineByLinePrinter; + var sideBySidePrinter = __webpack_require__(8).SideBySidePrinter; + + function HtmlPrinter() { + } + + HtmlPrinter.prototype.generateLineByLineJsonHtml = lineByLinePrinter.generateLineByLineJsonHtml; + + HtmlPrinter.prototype.generateSideBySideJsonHtml = sideBySidePrinter.generateSideBySideJsonHtml; + + module.exports['HtmlPrinter'] = new HtmlPrinter(); + + })(this); + + /***/ }, /* 7 */ +/***/ function(module, exports, __webpack_require__) { + + /* + * + * LineByLinePrinter (line-by-line-printer.js) + * Author: rtfpessoa + * + */ + + (function(ctx, undefined) { + + var diffParser = __webpack_require__(1).DiffParser; + var printerUtils = __webpack_require__(4).PrinterUtils; + var utils = __webpack_require__(2).Utils; + + function LineByLinePrinter() { + } + + LineByLinePrinter.prototype.generateLineByLineJsonHtml = function(diffFiles, config) { + return '
\n' + + diffFiles.map(function(file) { + + var diffs; + if (file.blocks.length) { + diffs = generateFileHtml(file, config); + } else { + diffs = generateEmptyDiff(); + } + + return '
\n' + + '
\n' + + '
\n' + + ' +' + file.addedLines + '\n' + + ' -' + file.deletedLines + '\n' + + '
\n' + + '
' + printerUtils.getDiffName(file) + '
\n' + + '
\n' + + '
\n' + + '
\n' + + ' \n' + + ' \n' + + ' ' + diffs + + ' \n' + + '
\n' + + '
\n' + + '
\n' + + '
\n'; + }).join('\n') + + '
\n'; + }; + + function generateFileHtml(file, config) { + return file.blocks.map(function(block) { + + var lines = '\n' + + ' \n' + + ' ' + + '
' + utils.escape(block.header) + '
' + + ' \n' + + '\n'; + + var oldLines = []; + var newLines = []; + var processedOldLines = []; + var processedNewLines = []; + + for (var i = 0; i < block.lines.length; i++) { + var line = block.lines[i]; + var escapedLine = utils.escape(line.content); + + if (line.type == diffParser.LINE_TYPE.CONTEXT && !oldLines.length && !newLines.length) { + lines += generateLineHtml(line.type, line.oldNumber, line.newNumber, escapedLine); + } else if (line.type == diffParser.LINE_TYPE.INSERTS && !oldLines.length && !newLines.length) { + lines += generateLineHtml(line.type, line.oldNumber, line.newNumber, escapedLine); + } else if (line.type == diffParser.LINE_TYPE.DELETES && !newLines.length) { + oldLines.push(line); + } else if (line.type == diffParser.LINE_TYPE.INSERTS && oldLines.length > newLines.length) { + newLines.push(line); + } else { + var j = 0; + var oldLine, newLine; + + if (oldLines.length === newLines.length) { + for (j = 0; j < oldLines.length; j++) { + oldLine = oldLines[j]; + newLine = newLines[j]; + + config.isCombined = file.isCombined; + var diff = printerUtils.diffHighlight(oldLine.content, newLine.content, config); + + processedOldLines += + generateLineHtml(oldLine.type, oldLine.oldNumber, oldLine.newNumber, + diff.first.line, diff.first.prefix); + processedNewLines += + generateLineHtml(newLine.type, newLine.oldNumber, newLine.newNumber, + diff.second.line, diff.second.prefix); + } + + lines += processedOldLines + processedNewLines; + } else { + lines += processLines(oldLines, newLines); + } + + oldLines = []; + newLines = []; + processedOldLines = []; + processedNewLines = []; + i--; + } + } + + lines += processLines(oldLines, newLines); + + return lines; + }).join('\n'); + } + + function processLines(oldLines, newLines) { + var lines = ''; + + for (j = 0; j < oldLines.length; j++) { + var oldLine = oldLines[j]; + var oldEscapedLine = utils.escape(oldLine.content); + lines += generateLineHtml(oldLine.type, oldLine.oldNumber, oldLine.newNumber, oldEscapedLine); + } + + for (j = 0; j < newLines.length; j++) { + var newLine = newLines[j]; + var newEscapedLine = utils.escape(newLine.content); + lines += generateLineHtml(newLine.type, newLine.oldNumber, newLine.newNumber, newEscapedLine); + } + + return lines; + } + + function generateLineHtml(type, oldNumber, newNumber, content, prefix) { + var htmlPrefix = ''; + if (prefix) { + htmlPrefix = '' + prefix + ''; + } + + var htmlContent = ''; + if (content) { + htmlContent = '' + content + ''; + } + + return '\n' + + ' ' + + '
' + utils.valueOrEmpty(oldNumber) + '
' + + '
' + utils.valueOrEmpty(newNumber) + '
' + + ' \n' + + ' ' + + '
' + htmlPrefix + htmlContent + '
' + + ' \n' + + '\n'; + } + + function generateEmptyDiff() { + return '\n' + + ' ' + + '
' + + 'File without changes' + + '
' + + ' \n' + + '\n'; + } + + module.exports['LineByLinePrinter'] = new LineByLinePrinter(); + + })(this); + + +/***/ }, +/* 8 */ /***/ function(module, exports, __webpack_require__) { /* @@ -1338,7 +1430,7 @@ (function(ctx, undefined) { var diffParser = __webpack_require__(1).DiffParser; - var printerUtils = __webpack_require__(5).PrinterUtils; + var printerUtils = __webpack_require__(4).PrinterUtils; var utils = __webpack_require__(2).Utils; function SideBySidePrinter() { @@ -1355,7 +1447,7 @@ diffs = generateEmptyDiff(); } - return '
\n' + + return '
\n' + '
\n' + '
\n' + ' +' + file.addedLines + '\n' + diff --git a/dist/diff2html.min.css b/dist/diff2html.min.css index 05eb930..ade5359 100644 --- a/dist/diff2html.min.css +++ b/dist/diff2html.min.css @@ -1 +1 @@ -.d2h-wrapper{display:block;margin:0 auto;text-align:left;width:100%}.d2h-file-wrapper{border:1px solid #ddd;border-radius:3px;margin-bottom:1em}.d2h-file-header{padding:5px 10px;border-bottom:1px solid #d8d8d8;background-color:#f7f7f7;font:13px Helvetica,arial,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"}.d2h-file-stats{display:inline;font-size:12px;text-align:center;max-width:15%}.d2h-lines-added{background-color:#ceffce;border:1px solid #b4e2b4;color:#399839;border-radius:5px 0 0 5px;padding:2px;width:25px}.d2h-lines-deleted{background-color:#f7c8c8;border:1px solid #e9aeae;color:#c33;border-radius:0 5px 5px 0;padding:2px;width:25px}.d2h-file-name{display:inline;height:33px;line-height:33px;max-width:80%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.d2h-diff-table{border-collapse:collapse;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:12px;height:18px;line-height:18px;width:100%}.d2h-files-diff{width:100%}.d2h-file-diff{overflow-x:scroll;overflow-y:hidden}.d2h-file-side-diff{display:inline-block;overflow-x:scroll;overflow-y:hidden;width:50%;margin-right:-4px}.d2h-code-line{display:block;white-space:pre;padding:0 10px;height:18px;line-height:18px;margin-left:80px;color:inherit;overflow-x:inherit;background:none}.d2h-code-side-line{display:block;white-space:pre;padding:0 10px;height:18px;line-height:18px;margin-left:50px;color:inherit;overflow-x:inherit;background:none}.d2h-code-line del,.d2h-code-side-line del{display:inline-block;margin-top:-1px;text-decoration:none;background-color:#ffb6ba;border-radius:.2em}.d2h-code-line ins,.d2h-code-side-line ins{display:inline-block;margin-top:-1px;text-decoration:none;background-color:#97f295;border-radius:.2em}.d2h-code-line-prefix{float:left;background:none;padding:0}.d2h-code-line-ctn{background:none;padding:0}.line-num1{display:inline-block;float:left;width:30px;overflow:hidden;text-overflow:ellipsis}.line-num2{display:inline-block;float:right;width:30px;overflow:hidden;text-overflow:ellipsis}.d2h-code-linenumber{position:absolute;width:2%;min-width:65px;padding-left:10px;padding-right:10px;height:18px;line-height:18px;background-color:#fff;color:rgba(0,0,0,0.3);text-align:right;border:solid #eee;border-width:0 1px 0 1px;cursor:pointer}.d2h-code-side-linenumber{position:absolute;width:35px;padding-left:10px;padding-right:10px;height:18px;line-height:18px;background-color:#fff;color:rgba(0,0,0,0.3);text-align:right;border:solid #eee;border-width:0 1px 0 1px;cursor:pointer;overflow:hidden;text-overflow:ellipsis}.d2h-del{background-color:#fee8e9;border-color:#e9aeae}.d2h-ins{background-color:#dfd;border-color:#b4e2b4}.d2h-info{background-color:#f8fafd;color:rgba(0,0,0,0.3);border-color:#d5e4f2} \ No newline at end of file +.d2h-wrapper{display:block;margin:0 auto;text-align:left;width:100%}.d2h-file-wrapper{border:1px solid #ddd;border-radius:3px;margin-bottom:1em}.d2h-file-header{padding:5px 10px;border-bottom:1px solid #d8d8d8;background-color:#f7f7f7;font:13px Helvetica,arial,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"}.d2h-file-stats{display:inline;font-size:12px;text-align:center;max-width:15%}.d2h-lines-added{background-color:#ceffce;border:1px solid #b4e2b4;color:#399839;border-radius:5px 0 0 5px;padding:2px;width:25px}.d2h-lines-deleted{background-color:#f7c8c8;border:1px solid #e9aeae;color:#c33;border-radius:0 5px 5px 0;padding:2px;width:25px}.d2h-file-name{display:inline;height:33px;line-height:33px;max-width:80%;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.d2h-diff-table{border-collapse:collapse;font-family:Consolas,"Liberation Mono",Menlo,Courier,monospace;font-size:12px;height:18px;line-height:18px;width:100%}.d2h-files-diff{width:100%}.d2h-file-diff{overflow-x:scroll;overflow-y:hidden}.d2h-file-side-diff{display:inline-block;overflow-x:scroll;overflow-y:hidden;width:50%;margin-right:-4px}.d2h-code-line{display:block;white-space:pre;padding:0 10px;height:18px;line-height:18px;margin-left:80px;color:inherit;overflow-x:inherit;background:none}.d2h-code-side-line{display:block;white-space:pre;padding:0 10px;height:18px;line-height:18px;margin-left:50px;color:inherit;overflow-x:inherit;background:none}.d2h-code-line del,.d2h-code-side-line del{display:inline-block;margin-top:-1px;text-decoration:none;background-color:#ffb6ba;border-radius:.2em}.d2h-code-line ins,.d2h-code-side-line ins{display:inline-block;margin-top:-1px;text-decoration:none;background-color:#97f295;border-radius:.2em}.d2h-code-line-prefix{float:left;background:none;padding:0}.d2h-code-line-ctn{background:none;padding:0}.line-num1{display:inline-block;float:left;width:30px;overflow:hidden;text-overflow:ellipsis}.line-num2{display:inline-block;float:right;width:30px;overflow:hidden;text-overflow:ellipsis}.d2h-code-linenumber{position:absolute;width:2%;min-width:65px;padding-left:10px;padding-right:10px;height:18px;line-height:18px;background-color:#fff;color:rgba(0,0,0,0.3);text-align:right;border:solid #eeeeee;border-width:0 1px 0 1px;cursor:pointer}.d2h-code-side-linenumber{position:absolute;width:35px;padding-left:10px;padding-right:10px;height:18px;line-height:18px;background-color:#fff;color:rgba(0,0,0,0.3);text-align:right;border:solid #eeeeee;border-width:0 1px 0 1px;cursor:pointer;overflow:hidden;text-overflow:ellipsis}.d2h-del{background-color:#fee8e9;border-color:#e9aeae}.d2h-ins{background-color:#dfd;border-color:#b4e2b4}.d2h-info{background-color:#f8fafd;color:rgba(0,0,0,0.3);border-color:#d5e4f2}.d2h-file-list-wrapper{margin-bottom:10px;padding:0 10px}.d2h-file-list-wrapper a{text-decoration:none;color:#3572b0}.d2h-file-list-wrapper a:visited{color:#3572b0}.d2h-file-list-header{font-weight:bold;margin-bottom:5px;text-align:left;display:inline;float:left}.d2h-file-list-line{text-align:left;font:13px Helvetica,arial,freesans,clean,sans-serif,"Segoe UI Emoji","Segoe UI Symbol"}.d2h-file-list-line .d2h-file-name{line-height:21px}.d2h-file-list{display:none}.d2h-clear{display:block;clear:both}.d2h-show{display:none;float:left}.d2h-hide{float:left}.d2h-hide:target+.d2h-show{display:inline}.d2h-hide:target{display:none}.d2h-hide:target~.d2h-file-list{display:block} \ No newline at end of file diff --git a/dist/diff2html.min.js b/dist/diff2html.min.js index 0786f08..361a63b 100644 --- a/dist/diff2html.min.js +++ b/dist/diff2html.min.js @@ -1 +1 @@ -!function(modules){function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:!1};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.loaded=!0,module.exports}var installedModules={};return __webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.p="",__webpack_require__(0)}([function(module,exports,__webpack_require__){(function(global){!function(){function Diff2Html(){}var diffParser=__webpack_require__(1).DiffParser,htmlPrinter=__webpack_require__(3).HtmlPrinter;Diff2Html.prototype.getPrettyHtmlFromDiff=function(diffInput,config){var diffJson=diffParser.generateDiffJson(diffInput),configOrEmpty=config||{};return htmlPrinter.generateLineByLineJsonHtml(diffJson,configOrEmpty)},Diff2Html.prototype.getJsonFromDiff=function(diffInput){return diffParser.generateDiffJson(diffInput)},Diff2Html.prototype.getPrettyHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return htmlPrinter.generateLineByLineJsonHtml(diffJson,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromDiff=function(diffInput,config){var diffJson=diffParser.generateDiffJson(diffInput),configOrEmpty=config||{};return htmlPrinter.generateSideBySideJsonHtml(diffJson,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return htmlPrinter.generateSideBySideJsonHtml(diffJson,configOrEmpty)};var diffName="Diff2Html",diffObject=new Diff2Html;module.exports[diffName]=diffObject,global[diffName]=diffObject}(this)}).call(exports,function(){return this}())},function(module,exports,__webpack_require__){!function(){function DiffParser(){}function getExtension(filename,language){var nameSplit=filename.split(".");return nameSplit.length>1?nameSplit[nameSplit.length-1]:language}var utils=__webpack_require__(2).Utils,LINE_TYPE={INSERTS:"d2h-ins",DELETES:"d2h-del",CONTEXT:"d2h-cntx",INFO:"d2h-info"};DiffParser.prototype.LINE_TYPE=LINE_TYPE,DiffParser.prototype.generateDiffJson=function(diffInput){var files=[],currentFile=null,currentBlock=null,oldLine=null,newLine=null,saveBlock=function(){currentBlock&&(currentFile.blocks.push(currentBlock),currentBlock=null)},saveFile=function(){currentFile&¤tFile.newName&&(files.push(currentFile),currentFile=null)},startFile=function(){saveBlock(),saveFile(),currentFile={},currentFile.blocks=[],currentFile.deletedLines=0,currentFile.addedLines=0},startBlock=function(line){saveBlock();var values;(values=/^@@ -(\d+),\d+ \+(\d+),\d+ @@.*/.exec(line))?currentFile.isCombined=!1:(values=/^@@@ -(\d+),\d+ -\d+,\d+ \+(\d+),\d+ @@@.*/.exec(line))?currentFile.isCombined=!0:(values=[0,0],currentFile.isCombined=!1),oldLine=values[1],newLine=values[2],currentBlock={},currentBlock.lines=[],currentBlock.oldStartLine=oldLine,currentBlock.newStartLine=newLine,currentBlock.header=line},createLine=function(line){var currentLine={};currentLine.content=line;var newLinePrefixes=currentFile.isCombined?["+"," +"]:["+"],delLinePrefixes=currentFile.isCombined?["-"," -"]:["-"];utils.startsWith(line,newLinePrefixes)?(currentFile.addedLines++,currentLine.type=LINE_TYPE.INSERTS,currentLine.oldNumber=null,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine)):utils.startsWith(line,delLinePrefixes)?(currentFile.deletedLines++,currentLine.type=LINE_TYPE.DELETES,currentLine.oldNumber=oldLine++,currentLine.newNumber=null,currentBlock.lines.push(currentLine)):(currentLine.type=LINE_TYPE.CONTEXT,currentLine.oldNumber=oldLine++,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine))},diffLines=diffInput.split("\n");return diffLines.forEach(function(line){if(line&&!utils.startsWith(line,"*")){var oldMode=/^old mode (\d{6})/,newMode=/^new mode (\d{6})/,deletedFileMode=/^deleted file mode (\d{6})/,newFileMode=/^new file mode (\d{6})/,copyFrom=/^copy from (.+)/,copyTo=/^copy to (.+)/,renameFrom=/^rename from (.+)/,renameTo=/^rename to (.+)/,similarityIndex=/^similarity index (\d+)%/,dissimilarityIndex=/^dissimilarity index (\d+)%/,index=/^index ([0-9a-z]+)..([0-9a-z]+) (\d{6})?/,combinedIndex=/^index ([0-9a-z]+),([0-9a-z]+)..([0-9a-z]+)/,combinedMode=/^mode (\d{6}),(\d{6})..(\d{6})/,combinedNewFile=/^new file mode (\d{6})/,combinedDeletedFile=/^deleted file mode (\d{6}),(\d{6})/,values=[];utils.startsWith(line,"diff")?startFile():currentFile&&!currentFile.oldName&&(values=/^--- [aiwco]\/(.+)$/.exec(line))?(currentFile.oldName=values[1],currentFile.language=getExtension(currentFile.oldName,currentFile.language)):currentFile&&!currentFile.newName&&(values=/^\+\+\+ [biwco]?\/(.+)$/.exec(line))?(currentFile.newName=values[1],currentFile.language=getExtension(currentFile.newName,currentFile.language)):currentFile&&utils.startsWith(line,"@@")?startBlock(line):(values=oldMode.exec(line))?currentFile.oldMode=values[1]:(values=newMode.exec(line))?currentFile.newMode=values[1]:(values=deletedFileMode.exec(line))?currentFile.deletedFileMode=values[1]:(values=newFileMode.exec(line))?currentFile.newFileMode=values[1]:(values=copyFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isCopy=!0):(values=copyTo.exec(line))?(currentFile.newName=values[1],currentFile.isCopy=!0):(values=renameFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isRename=!0):(values=renameTo.exec(line))?(currentFile.newName=values[1],currentFile.isRename=!0):(values=similarityIndex.exec(line))?currentFile.unchangedPercentage=values[1]:(values=dissimilarityIndex.exec(line))?currentFile.changedPercentage=values[1]:(values=index.exec(line))?(currentFile.checksumBefore=values[1],currentFile.checksumAfter=values[2],values[2]&&(currentFile.mode=values[3])):(values=combinedIndex.exec(line))?(currentFile.checksumBefore=[values[2],values[3]],currentFile.checksumAfter=values[1]):(values=combinedMode.exec(line))?(currentFile.oldMode=[values[2],values[3]],currentFile.newMode=values[1]):(values=combinedNewFile.exec(line))?currentFile.newFileMode=values[1]:(values=combinedDeletedFile.exec(line))?currentFile.deletedFileMode=values[1]:currentBlock&&createLine(line)}}),saveBlock(),saveFile(),files},module.exports.DiffParser=new DiffParser}(this)},function(module){!function(){function Utils(){}Utils.prototype.escape=function(str){return str.slice(0).replace(/&/g,"&").replace(//g,">").replace(/\t/g," ")},Utils.prototype.startsWith=function(str,start){if("object"==typeof start){var result=!1;return start.forEach(function(s){0===str.indexOf(s)&&(result=!0)}),result}return 0===str.indexOf(start)},Utils.prototype.valueOrEmpty=function(value){return value?value:""},module.exports.Utils=new Utils}(this)},function(module,exports,__webpack_require__){!function(){function HtmlPrinter(){}var lineByLinePrinter=__webpack_require__(4).LineByLinePrinter,sideBySidePrinter=__webpack_require__(7).SideBySidePrinter;HtmlPrinter.prototype.generateLineByLineJsonHtml=lineByLinePrinter.generateLineByLineJsonHtml,HtmlPrinter.prototype.generateSideBySideJsonHtml=sideBySidePrinter.generateSideBySideJsonHtml,module.exports.HtmlPrinter=new HtmlPrinter}(this)},function(module,exports,__webpack_require__){!function(){function LineByLinePrinter(){}function generateFileHtml(file,config){return file.blocks.map(function(block){for(var lines='\n \n
'+utils.escape(block.header)+"
\n\n",oldLines=[],newLines=[],processedOldLines=[],processedNewLines=[],i=0;inewLines.length)newLines.push(line);else{var oldLine,newLine,j=0;if(oldLines.length===newLines.length){for(j=0;j");var htmlContent="";return content&&(htmlContent=''+content+""),'\n
'+utils.valueOrEmpty(oldNumber)+'
'+utils.valueOrEmpty(newNumber)+'
\n
'+htmlPrefix+htmlContent+"
\n\n"}function generateEmptyDiff(){return'\n
File without changes
\n\n'}var diffParser=__webpack_require__(1).DiffParser,printerUtils=__webpack_require__(5).PrinterUtils,utils=__webpack_require__(2).Utils;LineByLinePrinter.prototype.generateLineByLineJsonHtml=function(diffFiles,config){return'
\n'+diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?generateFileHtml(file,config):generateEmptyDiff(),'
\n
\n
\n +'+file.addedLines+'\n -'+file.deletedLines+'\n
\n
'+printerUtils.getDiffName(file)+'
\n
\n
\n
\n \n \n '+diffs+" \n
\n
\n
\n
\n"}).join("\n")+"
\n"},module.exports.LineByLinePrinter=new LineByLinePrinter}(this)},function(module,exports,__webpack_require__){!function(){function PrinterUtils(){}function isDeletedName(name){return"dev/null"===name}function removeIns(line){return line.replace(/(((.|\n)*?)<\/ins>)/g,"")}function removeDel(line){return line.replace(/(((.|\n)*?)<\/del>)/g,"")}var jsDiff=__webpack_require__(6),utils=__webpack_require__(2).Utils;PrinterUtils.prototype.getDiffName=function(file){var oldFilename=file.oldName,newFilename=file.newName;return oldFilename&&newFilename&&oldFilename!==newFilename&&!isDeletedName(newFilename)?oldFilename+" -> "+newFilename:newFilename&&!isDeletedName(newFilename)?newFilename:oldFilename?oldFilename:"Unknown filename"},PrinterUtils.prototype.diffHighlight=function(diffLine1,diffLine2,config){var lineStart1,lineStart2,prefixSize=1;config.isCombined&&(prefixSize=2),lineStart1=diffLine1.substr(0,prefixSize),lineStart2=diffLine2.substr(0,prefixSize),diffLine1=diffLine1.substr(prefixSize),diffLine2=diffLine2.substr(prefixSize);var diff;diff=config.charByChar?jsDiff.diffChars(diffLine1,diffLine2):jsDiff.diffWordsWithSpace(diffLine1,diffLine2);var highlightedLine="";return diff.forEach(function(part){var elemType=part.added?"ins":part.removed?"del":null,escapedValue=utils.escape(part.value);highlightedLine+=null!==elemType?"<"+elemType+">"+escapedValue+"":escapedValue}),{first:{prefix:lineStart1,line:removeIns(highlightedLine)},second:{prefix:lineStart2,line:removeDel(highlightedLine)}}},module.exports.PrinterUtils=new PrinterUtils}(this)},function(module,exports){var __WEBPACK_AMD_DEFINE_ARRAY__,__WEBPACK_AMD_DEFINE_RESULT__;!function(global,undefined){function map(arr,mapper,that){if(Array.prototype.map)return Array.prototype.map.call(arr,mapper,that);for(var other=new Array(arr.length),i=0,n=arr.length;n>i;i++)other[i]=mapper.call(that,arr[i],i,arr);return other}function clonePath(path){return{newPos:path.newPos,components:path.components.slice(0)}}function removeEmpty(array){for(var ret=[],i=0;i/g,">"),n=n.replace(/"/g,""")}function canonicalize(obj,stack,replacementStack){stack=stack||[],replacementStack=replacementStack||[];var i;for(i=0;icomponentPos;componentPos++){var component=components[componentPos];if(component.removed){if(component.value=oldString.slice(oldPos,oldPos+component.count).join(""),oldPos+=component.count,componentPos&&components[componentPos-1].added){var tmp=components[componentPos-1];components[componentPos-1]=components[componentPos],components[componentPos]=tmp}}else{if(!component.added&&useLongestToken){var value=newString.slice(newPos,newPos+component.count);value=map(value,function(value,i){var oldValue=oldString[oldPos+i];return oldValue.length>value.length?oldValue:value}),component.value=value.join("")}else component.value=newString.slice(newPos,newPos+component.count).join("");newPos+=component.count,component.added||(oldPos+=component.count)}}return components}function Diff(ignoreWhitespace){this.ignoreWhitespace=ignoreWhitespace}var objectPrototypeToString=Object.prototype.toString;Diff.prototype={diff:function(oldString,newString,callback){function done(value){return callback?(setTimeout(function(){callback(undefined,value)},0),!0):value}function execEditLength(){for(var diagonalPath=-1*editLength;editLength>=diagonalPath;diagonalPath+=2){var basePath,addPath=bestPath[diagonalPath-1],removePath=bestPath[diagonalPath+1],oldPos=(removePath?removePath.newPos:0)-diagonalPath;addPath&&(bestPath[diagonalPath-1]=undefined);var canAdd=addPath&&addPath.newPos+1=0&&oldLen>oldPos;if(canAdd||canRemove){if(!canAdd||canRemove&&addPath.newPos=newLen&&oldPos+1>=oldLen)return done(buildValues(basePath.components,newString,oldString,self.useLongestToken));bestPath[diagonalPath]=basePath}else bestPath[diagonalPath]=undefined}editLength++}var self=this;if(newString===oldString)return done([{value:newString}]);if(!newString)return done([{value:oldString,removed:!0}]);if(!oldString)return done([{value:newString,added:!0}]);newString=this.tokenize(newString),oldString=this.tokenize(oldString);var newLen=newString.length,oldLen=oldString.length,editLength=1,maxEditLength=newLen+oldLen,bestPath=[{newPos:-1,components:[]}],oldPos=this.extractCommon(bestPath[0],newString,oldString,0);if(bestPath[0].newPos+1>=newLen&&oldPos+1>=oldLen)return done([{value:newString.join("")}]);if(callback)!function exec(){setTimeout(function(){return editLength>maxEditLength?callback():void(execEditLength()||exec())},0)}();else for(;maxEditLength>=editLength;){var ret=execEditLength();if(ret)return ret}},pushComponent:function(components,added,removed){var last=components[components.length-1];last&&last.added===added&&last.removed===removed?components[components.length-1]={count:last.count+1,added:added,removed:removed}:components.push({count:1,added:added,removed:removed})},extractCommon:function(basePath,newString,oldString,diagonalPath){for(var newLen=newString.length,oldLen=oldString.length,newPos=basePath.newPos,oldPos=newPos-diagonalPath,commonCount=0;newLen>newPos+1&&oldLen>oldPos+1&&this.equals(newString[newPos+1],oldString[oldPos+1]);)newPos++,oldPos++,commonCount++;return commonCount&&basePath.components.push({count:commonCount}),basePath.newPos=newPos,oldPos},equals:function(left,right){var reWhitespace=/\S/;return left===right||this.ignoreWhitespace&&!reWhitespace.test(left)&&!reWhitespace.test(right)},tokenize:function(value){return value.split("")}};var CharDiff=new Diff,WordDiff=new Diff(!0),WordWithSpaceDiff=new Diff;WordDiff.tokenize=WordWithSpaceDiff.tokenize=function(value){return removeEmpty(value.split(/(\s+|\b)/))};var CssDiff=new Diff(!0);CssDiff.tokenize=function(value){return removeEmpty(value.split(/([{}:;,]|\s+)/))};var LineDiff=new Diff,TrimmedLineDiff=new Diff;TrimmedLineDiff.ignoreTrim=!0,LineDiff.tokenize=TrimmedLineDiff.tokenize=function(value){for(var retLines=[],lines=value.split(/^/m),i=0;i=0;i--){for(var hunk=hunks[i],j=0;j"):change.removed&&ret.push(""),ret.push(escapeHTML(change.value)),change.added?ret.push(""):change.removed&&ret.push("")}return ret.join("")},convertChangesToDMP:function(changes){for(var change,operation,ret=[],i=0;i\n
'+utils.escape(block.header)+"
\n\n",fileHtml.right+='\n \n
\n\n';for(var oldLines=[],newLines=[],tmpHtml="",i=0;inewLines.length)newLines.push(line);else{var oldLine,newLine,j=0;if(oldLines.length===newLines.length)for(j=0;j");var htmlContent="";return content&&(htmlContent=''+content+""),'\n '+number+'\n
'+htmlPrefix+htmlContent+"
\n \n"}function generateEmptyDiff(){var fileHtml={};return fileHtml.right="",fileHtml.left='\n
File without changes
\n\n',fileHtml}var diffParser=__webpack_require__(1).DiffParser,printerUtils=__webpack_require__(5).PrinterUtils,utils=__webpack_require__(2).Utils;SideBySidePrinter.prototype.generateSideBySideJsonHtml=function(diffFiles,config){return'
\n'+diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?generateSideBySideFileHtml(file,config):generateEmptyDiff(),'
\n
\n
\n +'+file.addedLines+'\n -'+file.deletedLines+'\n
\n
'+printerUtils.getDiffName(file)+'
\n
\n
\n
\n
\n \n \n '+diffs.left+' \n
\n
\n
\n
\n
\n \n \n '+diffs.right+" \n
\n
\n
\n
\n
\n"}).join("\n")+"
\n"},module.exports.SideBySidePrinter=new SideBySidePrinter}(this)}]); \ No newline at end of file +!function(modules){function __webpack_require__(moduleId){if(installedModules[moduleId])return installedModules[moduleId].exports;var module=installedModules[moduleId]={exports:{},id:moduleId,loaded:!1};return modules[moduleId].call(module.exports,module,module.exports,__webpack_require__),module.loaded=!0,module.exports}var installedModules={};return __webpack_require__.m=modules,__webpack_require__.c=installedModules,__webpack_require__.p="",__webpack_require__(0)}([function(module,exports,__webpack_require__){(function(global){!function(){function Diff2Html(){}var diffParser=__webpack_require__(1).DiffParser,fileLister=__webpack_require__(3).FileListPrinter,htmlPrinter=__webpack_require__(6).HtmlPrinter;Diff2Html.prototype.getJsonFromDiff=function(diffInput){return diffParser.generateDiffJson(diffInput)},Diff2Html.prototype.getPrettyHtml=function(diffInput,config){var configOrEmpty=config||{},diffJson=diffInput;configOrEmpty.inputFormat&&"diff"!==configOrEmpty.inputFormat||(diffJson=diffParser.generateDiffJson(diffInput));var fileList="";configOrEmpty.showFiles===!0&&(fileList=fileLister.generateFileList(diffJson,configOrEmpty));var diffOutput="";return diffOutput="side-by-side"===configOrEmpty.outputFormat?htmlPrinter.generateSideBySideJsonHtml(diffJson,configOrEmpty):htmlPrinter.generateLineByLineJsonHtml(diffJson,configOrEmpty),fileList+diffOutput},Diff2Html.prototype.getPrettyHtmlFromDiff=function(diffInput,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat="diff",configOrEmpty.outputFormat="line-by-line",this.getPrettyHtml(diffInput,configOrEmpty)},Diff2Html.prototype.getPrettyHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat="json",configOrEmpty.outputFormat="line-by-line",this.getPrettyHtml(diffJson,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromDiff=function(diffInput,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat="diff",configOrEmpty.outputFormat="side-by-side",this.getPrettyHtml(diffInput,configOrEmpty)},Diff2Html.prototype.getPrettySideBySideHtmlFromJson=function(diffJson,config){var configOrEmpty=config||{};return configOrEmpty.inputFormat="json",configOrEmpty.outputFormat="side-by-side",this.getPrettyHtml(diffJson,configOrEmpty)};var diffName="Diff2Html",diffObject=new Diff2Html;module.exports[diffName]=diffObject,global[diffName]=diffObject}(this)}).call(exports,function(){return this}())},function(module,exports,__webpack_require__){!function(){function DiffParser(){}function getExtension(filename,language){var nameSplit=filename.split(".");return nameSplit.length>1?nameSplit[nameSplit.length-1]:language}var utils=__webpack_require__(2).Utils,LINE_TYPE={INSERTS:"d2h-ins",DELETES:"d2h-del",CONTEXT:"d2h-cntx",INFO:"d2h-info"};DiffParser.prototype.LINE_TYPE=LINE_TYPE,DiffParser.prototype.generateDiffJson=function(diffInput){var files=[],currentFile=null,currentBlock=null,oldLine=null,newLine=null,saveBlock=function(){currentBlock&&(currentFile.blocks.push(currentBlock),currentBlock=null)},saveFile=function(){currentFile&¤tFile.newName&&(files.push(currentFile),currentFile=null)},startFile=function(){saveBlock(),saveFile(),currentFile={},currentFile.blocks=[],currentFile.deletedLines=0,currentFile.addedLines=0},startBlock=function(line){saveBlock();var values;(values=/^@@ -(\d+),\d+ \+(\d+),\d+ @@.*/.exec(line))?currentFile.isCombined=!1:(values=/^@@@ -(\d+),\d+ -\d+,\d+ \+(\d+),\d+ @@@.*/.exec(line))?currentFile.isCombined=!0:(values=[0,0],currentFile.isCombined=!1),oldLine=values[1],newLine=values[2],currentBlock={},currentBlock.lines=[],currentBlock.oldStartLine=oldLine,currentBlock.newStartLine=newLine,currentBlock.header=line},createLine=function(line){var currentLine={};currentLine.content=line;var newLinePrefixes=currentFile.isCombined?["+"," +"]:["+"],delLinePrefixes=currentFile.isCombined?["-"," -"]:["-"];utils.startsWith(line,newLinePrefixes)?(currentFile.addedLines++,currentLine.type=LINE_TYPE.INSERTS,currentLine.oldNumber=null,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine)):utils.startsWith(line,delLinePrefixes)?(currentFile.deletedLines++,currentLine.type=LINE_TYPE.DELETES,currentLine.oldNumber=oldLine++,currentLine.newNumber=null,currentBlock.lines.push(currentLine)):(currentLine.type=LINE_TYPE.CONTEXT,currentLine.oldNumber=oldLine++,currentLine.newNumber=newLine++,currentBlock.lines.push(currentLine))},diffLines=diffInput.split("\n");return diffLines.forEach(function(line){if(line&&!utils.startsWith(line,"*")){var oldMode=/^old mode (\d{6})/,newMode=/^new mode (\d{6})/,deletedFileMode=/^deleted file mode (\d{6})/,newFileMode=/^new file mode (\d{6})/,copyFrom=/^copy from (.+)/,copyTo=/^copy to (.+)/,renameFrom=/^rename from (.+)/,renameTo=/^rename to (.+)/,similarityIndex=/^similarity index (\d+)%/,dissimilarityIndex=/^dissimilarity index (\d+)%/,index=/^index ([0-9a-z]+)..([0-9a-z]+) (\d{6})?/,combinedIndex=/^index ([0-9a-z]+),([0-9a-z]+)..([0-9a-z]+)/,combinedMode=/^mode (\d{6}),(\d{6})..(\d{6})/,combinedNewFile=/^new file mode (\d{6})/,combinedDeletedFile=/^deleted file mode (\d{6}),(\d{6})/,values=[];utils.startsWith(line,"diff")?startFile():currentFile&&!currentFile.oldName&&(values=/^--- [aiwco]\/(.+)$/.exec(line))?(currentFile.oldName=values[1],currentFile.language=getExtension(currentFile.oldName,currentFile.language)):currentFile&&!currentFile.newName&&(values=/^\+\+\+ [biwco]?\/(.+)$/.exec(line))?(currentFile.newName=values[1],currentFile.language=getExtension(currentFile.newName,currentFile.language)):currentFile&&utils.startsWith(line,"@@")?startBlock(line):(values=oldMode.exec(line))?currentFile.oldMode=values[1]:(values=newMode.exec(line))?currentFile.newMode=values[1]:(values=deletedFileMode.exec(line))?currentFile.deletedFileMode=values[1]:(values=newFileMode.exec(line))?currentFile.newFileMode=values[1]:(values=copyFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isCopy=!0):(values=copyTo.exec(line))?(currentFile.newName=values[1],currentFile.isCopy=!0):(values=renameFrom.exec(line))?(currentFile.oldName=values[1],currentFile.isRename=!0):(values=renameTo.exec(line))?(currentFile.newName=values[1],currentFile.isRename=!0):(values=similarityIndex.exec(line))?currentFile.unchangedPercentage=values[1]:(values=dissimilarityIndex.exec(line))?currentFile.changedPercentage=values[1]:(values=index.exec(line))?(currentFile.checksumBefore=values[1],currentFile.checksumAfter=values[2],values[2]&&(currentFile.mode=values[3])):(values=combinedIndex.exec(line))?(currentFile.checksumBefore=[values[2],values[3]],currentFile.checksumAfter=values[1]):(values=combinedMode.exec(line))?(currentFile.oldMode=[values[2],values[3]],currentFile.newMode=values[1]):(values=combinedNewFile.exec(line))?currentFile.newFileMode=values[1]:(values=combinedDeletedFile.exec(line))?currentFile.deletedFileMode=values[1]:currentBlock&&createLine(line)}}),saveBlock(),saveFile(),files},module.exports.DiffParser=new DiffParser}(this)},function(module){!function(){function Utils(){}Utils.prototype.escape=function(str){return str.slice(0).replace(/&/g,"&").replace(//g,">").replace(/\t/g," ")},Utils.prototype.getRandomId=function(prefix){return prefix+"-"+Math.random().toString(36).slice(-3)},Utils.prototype.startsWith=function(str,start){if("object"==typeof start){var result=!1;return start.forEach(function(s){0===str.indexOf(s)&&(result=!0)}),result}return 0===str.indexOf(start)},Utils.prototype.valueOrEmpty=function(value){return value?value:""},module.exports.Utils=new Utils}(this)},function(module,exports,__webpack_require__){!function(){function FileListPrinter(){}var printerUtils=__webpack_require__(4).PrinterUtils,utils=__webpack_require__(2).Utils;FileListPrinter.prototype.generateFileList=function(diffFiles){var hideId=utils.getRandomId("d2h-hide"),showId=utils.getRandomId("d2h-show");return'
\n
Files changed ('+diffFiles.length+')  
\n +\n -\n
\n
\n'+diffFiles.map(function(file){return'
\n
\n +'+file.addedLines+'\n -'+file.deletedLines+'\n
\n \n
\n"}).join("\n")+"
\n"},module.exports.FileListPrinter=new FileListPrinter}(this)},function(module,exports,__webpack_require__){!function(){function PrinterUtils(){}function isDeletedName(name){return"dev/null"===name}function removeIns(line){return line.replace(/(((.|\n)*?)<\/ins>)/g,"")}function removeDel(line){return line.replace(/(((.|\n)*?)<\/del>)/g,"")}var jsDiff=__webpack_require__(5),utils=__webpack_require__(2).Utils;PrinterUtils.prototype.getHtmlId=function(file){return"d2h-"+this.getDiffName(file)},PrinterUtils.prototype.getDiffName=function(file){var oldFilename=file.oldName,newFilename=file.newName;return oldFilename&&newFilename&&oldFilename!==newFilename&&!isDeletedName(newFilename)?oldFilename+" -> "+newFilename:newFilename&&!isDeletedName(newFilename)?newFilename:oldFilename?oldFilename:"Unknown filename"},PrinterUtils.prototype.diffHighlight=function(diffLine1,diffLine2,config){var lineStart1,lineStart2,prefixSize=1;config.isCombined&&(prefixSize=2),lineStart1=diffLine1.substr(0,prefixSize),lineStart2=diffLine2.substr(0,prefixSize),diffLine1=diffLine1.substr(prefixSize),diffLine2=diffLine2.substr(prefixSize);var diff;diff=config.charByChar?jsDiff.diffChars(diffLine1,diffLine2):jsDiff.diffWordsWithSpace(diffLine1,diffLine2);var highlightedLine="";return diff.forEach(function(part){var elemType=part.added?"ins":part.removed?"del":null,escapedValue=utils.escape(part.value);highlightedLine+=null!==elemType?"<"+elemType+">"+escapedValue+"":escapedValue}),{first:{prefix:lineStart1,line:removeIns(highlightedLine)},second:{prefix:lineStart2,line:removeDel(highlightedLine)}}},module.exports.PrinterUtils=new PrinterUtils}(this)},function(module,exports){var __WEBPACK_AMD_DEFINE_ARRAY__,__WEBPACK_AMD_DEFINE_RESULT__;!function(global,undefined){function map(arr,mapper,that){if(Array.prototype.map)return Array.prototype.map.call(arr,mapper,that);for(var other=new Array(arr.length),i=0,n=arr.length;n>i;i++)other[i]=mapper.call(that,arr[i],i,arr);return other}function clonePath(path){return{newPos:path.newPos,components:path.components.slice(0)}}function removeEmpty(array){for(var ret=[],i=0;i/g,">"),n=n.replace(/"/g,""")}function canonicalize(obj,stack,replacementStack){stack=stack||[],replacementStack=replacementStack||[];var i;for(i=0;icomponentPos;componentPos++){var component=components[componentPos];if(component.removed){if(component.value=oldString.slice(oldPos,oldPos+component.count).join(""),oldPos+=component.count,componentPos&&components[componentPos-1].added){var tmp=components[componentPos-1];components[componentPos-1]=components[componentPos],components[componentPos]=tmp}}else{if(!component.added&&useLongestToken){var value=newString.slice(newPos,newPos+component.count);value=map(value,function(value,i){var oldValue=oldString[oldPos+i];return oldValue.length>value.length?oldValue:value}),component.value=value.join("")}else component.value=newString.slice(newPos,newPos+component.count).join("");newPos+=component.count,component.added||(oldPos+=component.count)}}return components}function Diff(ignoreWhitespace){this.ignoreWhitespace=ignoreWhitespace}var objectPrototypeToString=Object.prototype.toString;Diff.prototype={diff:function(oldString,newString,callback){function done(value){return callback?(setTimeout(function(){callback(undefined,value)},0),!0):value}function execEditLength(){for(var diagonalPath=-1*editLength;editLength>=diagonalPath;diagonalPath+=2){var basePath,addPath=bestPath[diagonalPath-1],removePath=bestPath[diagonalPath+1],oldPos=(removePath?removePath.newPos:0)-diagonalPath;addPath&&(bestPath[diagonalPath-1]=undefined);var canAdd=addPath&&addPath.newPos+1=0&&oldLen>oldPos;if(canAdd||canRemove){if(!canAdd||canRemove&&addPath.newPos=newLen&&oldPos+1>=oldLen)return done(buildValues(basePath.components,newString,oldString,self.useLongestToken));bestPath[diagonalPath]=basePath}else bestPath[diagonalPath]=undefined}editLength++}var self=this;if(newString===oldString)return done([{value:newString}]);if(!newString)return done([{value:oldString,removed:!0}]);if(!oldString)return done([{value:newString,added:!0}]);newString=this.tokenize(newString),oldString=this.tokenize(oldString);var newLen=newString.length,oldLen=oldString.length,editLength=1,maxEditLength=newLen+oldLen,bestPath=[{newPos:-1,components:[]}],oldPos=this.extractCommon(bestPath[0],newString,oldString,0);if(bestPath[0].newPos+1>=newLen&&oldPos+1>=oldLen)return done([{value:newString.join("")}]);if(callback)!function exec(){setTimeout(function(){return editLength>maxEditLength?callback():void(execEditLength()||exec())},0)}();else for(;maxEditLength>=editLength;){var ret=execEditLength();if(ret)return ret}},pushComponent:function(components,added,removed){var last=components[components.length-1];last&&last.added===added&&last.removed===removed?components[components.length-1]={count:last.count+1,added:added,removed:removed}:components.push({count:1,added:added,removed:removed})},extractCommon:function(basePath,newString,oldString,diagonalPath){for(var newLen=newString.length,oldLen=oldString.length,newPos=basePath.newPos,oldPos=newPos-diagonalPath,commonCount=0;newLen>newPos+1&&oldLen>oldPos+1&&this.equals(newString[newPos+1],oldString[oldPos+1]);)newPos++,oldPos++,commonCount++;return commonCount&&basePath.components.push({count:commonCount}),basePath.newPos=newPos,oldPos},equals:function(left,right){var reWhitespace=/\S/;return left===right||this.ignoreWhitespace&&!reWhitespace.test(left)&&!reWhitespace.test(right)},tokenize:function(value){return value.split("")}};var CharDiff=new Diff,WordDiff=new Diff(!0),WordWithSpaceDiff=new Diff;WordDiff.tokenize=WordWithSpaceDiff.tokenize=function(value){return removeEmpty(value.split(/(\s+|\b)/))};var CssDiff=new Diff(!0);CssDiff.tokenize=function(value){return removeEmpty(value.split(/([{}:;,]|\s+)/))};var LineDiff=new Diff,TrimmedLineDiff=new Diff;TrimmedLineDiff.ignoreTrim=!0,LineDiff.tokenize=TrimmedLineDiff.tokenize=function(value){for(var retLines=[],lines=value.split(/^/m),i=0;i=0;i--){for(var hunk=hunks[i],j=0;j"):change.removed&&ret.push(""),ret.push(escapeHTML(change.value)),change.added?ret.push(""):change.removed&&ret.push("")}return ret.join("")},convertChangesToDMP:function(changes){for(var change,operation,ret=[],i=0;i\n
'+utils.escape(block.header)+"
\n\n",oldLines=[],newLines=[],processedOldLines=[],processedNewLines=[],i=0;inewLines.length)newLines.push(line);else{var oldLine,newLine,j=0;if(oldLines.length===newLines.length){for(j=0;j");var htmlContent="";return content&&(htmlContent=''+content+""),'\n
'+utils.valueOrEmpty(oldNumber)+'
'+utils.valueOrEmpty(newNumber)+'
\n
'+htmlPrefix+htmlContent+"
\n\n"}function generateEmptyDiff(){return'\n
File without changes
\n\n'}var diffParser=__webpack_require__(1).DiffParser,printerUtils=__webpack_require__(4).PrinterUtils,utils=__webpack_require__(2).Utils;LineByLinePrinter.prototype.generateLineByLineJsonHtml=function(diffFiles,config){return'
\n'+diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?generateFileHtml(file,config):generateEmptyDiff(),'
\n
\n
\n +'+file.addedLines+'\n -'+file.deletedLines+'\n
\n
'+printerUtils.getDiffName(file)+'
\n
\n
\n
\n \n \n '+diffs+" \n
\n
\n
\n
\n"}).join("\n")+"
\n"},module.exports.LineByLinePrinter=new LineByLinePrinter}(this)},function(module,exports,__webpack_require__){!function(){function SideBySidePrinter(){}function generateSideBySideFileHtml(file,config){var fileHtml={};return fileHtml.left="",fileHtml.right="",file.blocks.forEach(function(block){fileHtml.left+='\n \n
'+utils.escape(block.header)+"
\n\n",fileHtml.right+='\n \n
\n\n';for(var oldLines=[],newLines=[],tmpHtml="",i=0;inewLines.length)newLines.push(line);else{var oldLine,newLine,j=0;if(oldLines.length===newLines.length)for(j=0;j");var htmlContent="";return content&&(htmlContent=''+content+""),'\n '+number+'\n
'+htmlPrefix+htmlContent+"
\n \n"}function generateEmptyDiff(){var fileHtml={};return fileHtml.right="",fileHtml.left='\n
File without changes
\n\n',fileHtml}var diffParser=__webpack_require__(1).DiffParser,printerUtils=__webpack_require__(4).PrinterUtils,utils=__webpack_require__(2).Utils;SideBySidePrinter.prototype.generateSideBySideJsonHtml=function(diffFiles,config){return'
\n'+diffFiles.map(function(file){var diffs;return diffs=file.blocks.length?generateSideBySideFileHtml(file,config):generateEmptyDiff(),'
\n
\n
\n +'+file.addedLines+'\n -'+file.deletedLines+'\n
\n
'+printerUtils.getDiffName(file)+'
\n
\n
\n
\n
\n \n \n '+diffs.left+' \n
\n
\n
\n
\n
\n \n \n '+diffs.right+" \n
\n
\n
\n
\n
\n"}).join("\n")+"
\n"},module.exports.SideBySidePrinter=new SideBySidePrinter}(this)}]); \ No newline at end of file diff --git a/sample/index.html b/sample/index.html index 920462f..4f3c91b 100644 --- a/sample/index.html +++ b/sample/index.html @@ -245,8 +245,8 @@ hljs.configure({languages: distinctLanguages}); // generate and inject the diff HTML into the desired place - document.getElementById("line-by-line").innerHTML = Diff2Html.getPrettyHtmlFromJson(diffJson); - document.getElementById("side-by-side").innerHTML = Diff2Html.getPrettySideBySideHtmlFromJson(diffJson); + document.getElementById("line-by-line").innerHTML = Diff2Html.getPrettyHtml(diffJson, { inputFormat: 'json', showFiles: true }); + document.getElementById("side-by-side").innerHTML = Diff2Html.getPrettyHtml(diffJson, { inputFormat: 'json', outputFormat: 'side-by-side' }); // collect all the code lines and execute the highlight on them var codeLines = document.getElementsByClassName("d2h-code-line-ctn"); diff --git a/src/diff2html.js b/src/diff2html.js index 23fad78..7914f0f 100644 --- a/src/diff2html.js +++ b/src/diff2html.js @@ -8,6 +8,7 @@ (function(ctx, undefined) { var diffParser = require('./diff-parser.js').DiffParser; + var fileLister = require('./file-list-printer.js').FileListPrinter; var htmlPrinter = require('./html-printer.js').HtmlPrinter; function Diff2Html() { @@ -22,15 +23,6 @@ }; */ - /* - * Generates pretty html from string diff input - */ - Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) { - var diffJson = diffParser.generateDiffJson(diffInput); - var configOrEmpty = config || {}; - return htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); - }; - /* * Generates json object from string diff input */ @@ -38,22 +30,65 @@ return diffParser.generateDiffJson(diffInput); }; + /* + * Generates the html diff. The config parameter configures the output/input formats and other options + */ + Diff2Html.prototype.getPrettyHtml = function(diffInput, config) { + var configOrEmpty = config || {}; + + var diffJson = diffInput; + if(!configOrEmpty.inputFormat || configOrEmpty.inputFormat === 'diff') { + diffJson = diffParser.generateDiffJson(diffInput); + } + + var fileList = ""; + if(configOrEmpty.showFiles === true) { + fileList = fileLister.generateFileList(diffJson, configOrEmpty); + } + + var diffOutput = ""; + if(configOrEmpty.outputFormat === 'side-by-side') { + diffOutput = htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + } else { + diffOutput = htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); + } + + return fileList + diffOutput + }; + + + /* + * Deprecated methods - The following methods exist only to maintain compatibility with previous versions + */ + + /* + * Generates pretty html from string diff input + */ + Diff2Html.prototype.getPrettyHtmlFromDiff = function(diffInput, config) { + var configOrEmpty = config || {}; + configOrEmpty['inputFormat'] = 'diff'; + configOrEmpty['outputFormat'] = 'line-by-line'; + return this.getPrettyHtml(diffInput, configOrEmpty) + }; + /* * Generates pretty html from a json object */ Diff2Html.prototype.getPrettyHtmlFromJson = function(diffJson, config) { var configOrEmpty = config || {}; - return htmlPrinter.generateLineByLineJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'json'; + configOrEmpty['outputFormat'] = 'line-by-line'; + return this.getPrettyHtml(diffJson, configOrEmpty) }; /* * Generates pretty side by side html from string diff input */ Diff2Html.prototype.getPrettySideBySideHtmlFromDiff = function(diffInput, config) { - var diffJson = diffParser.generateDiffJson(diffInput); - var configOrEmpty = config || {}; - return htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'diff'; + configOrEmpty['outputFormat'] = 'side-by-side'; + return this.getPrettyHtml(diffInput, configOrEmpty) }; /* @@ -61,7 +96,9 @@ */ Diff2Html.prototype.getPrettySideBySideHtmlFromJson = function(diffJson, config) { var configOrEmpty = config || {}; - return htmlPrinter.generateSideBySideJsonHtml(diffJson, configOrEmpty); + configOrEmpty['inputFormat'] = 'json'; + configOrEmpty['outputFormat'] = 'side-by-side'; + return this.getPrettyHtml(diffJson, configOrEmpty) }; var diffName = 'Diff2Html'; diff --git a/src/file-list-printer.js b/src/file-list-printer.js new file mode 100644 index 0000000..0dd3e7d --- /dev/null +++ b/src/file-list-printer.js @@ -0,0 +1,41 @@ +/* + * + * FileListPrinter (file-list-printer.js) + * Author: nmatpt + * + */ + +(function (ctx, undefined) { + + var printerUtils = require('./printer-utils.js').PrinterUtils; + var utils = require('./utils.js').Utils; + + function FileListPrinter() { + } + + FileListPrinter.prototype.generateFileList = function (diffFiles) { + var hideId = utils.getRandomId("d2h-hide"); + var showId = utils.getRandomId("d2h-show"); + return '
\n' + + '
Files changed (' + diffFiles.length + ')  
\n' + + ' +\n' + + ' -\n' + + '
\n' + + '
\n' + + + + diffFiles.map(function (file) { + return '
\n' + + '
\n' + + ' +' + file.addedLines + '\n' + + ' -' + file.deletedLines + '\n' + + '
\n' + + ' \n' + + '
\n' + }).join('\n') + + '
\n'; + }; + + module.exports['FileListPrinter'] = new FileListPrinter(); + +})(this); diff --git a/src/line-by-line-printer.js b/src/line-by-line-printer.js index bc5a1a0..5b5a78f 100644 --- a/src/line-by-line-printer.js +++ b/src/line-by-line-printer.js @@ -25,7 +25,7 @@ diffs = generateEmptyDiff(); } - return '
\n' + + return '
\n' + '
\n' + '
\n' + ' +' + file.addedLines + '\n' + diff --git a/src/printer-utils.js b/src/printer-utils.js index 5b5b98b..2f2ea8d 100644 --- a/src/printer-utils.js +++ b/src/printer-utils.js @@ -13,6 +13,10 @@ function PrinterUtils() { } + PrinterUtils.prototype.getHtmlId = function(file) { + return "d2h-" + this.getDiffName(file); + }; + PrinterUtils.prototype.getDiffName = function(file) { var oldFilename = file.oldName; var newFilename = file.newName; diff --git a/src/side-by-side-printer.js b/src/side-by-side-printer.js index 1563812..ca5dcbe 100644 --- a/src/side-by-side-printer.js +++ b/src/side-by-side-printer.js @@ -25,7 +25,7 @@ diffs = generateEmptyDiff(); } - return '
\n' + + return '
\n' + '
\n' + '
\n' + ' +' + file.addedLines + '\n' + diff --git a/src/utils.js b/src/utils.js index 418b93c..7f91ff1 100644 --- a/src/utils.js +++ b/src/utils.js @@ -18,6 +18,10 @@ .replace(/\t/g, ' '); }; + Utils.prototype.getRandomId = function(prefix) { + return prefix + "-" + Math.random().toString(36).slice(-3); + }; + Utils.prototype.startsWith = function(str, start) { if (typeof start === 'object') { var result = false;