diff2html/website/templates/pages/demo/demo.js

245 lines
8.5 KiB
JavaScript
Raw Normal View History

2019-10-13 18:21:19 +00:00
/* global global */
2019-10-12 21:45:49 +00:00
/* eslint-disable @typescript-eslint/explicit-function-return-type */
2016-10-12 22:55:31 +00:00
2016-10-12 21:52:59 +00:00
/*
* Example URLs:
*
* https://github.com/rtfpessoa/diff2html/commit/7d02e67f3b3386ac5d804f974d025cd7a1165839
* https://github.com/rtfpessoa/diff2html/pull/106
*
* https://gitlab.com/gitlab-org/gitlab-ce/commit/4e963fed42ad518caa7353d361a38a1250c99c41
* https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/6763
*
* https://bitbucket.org/atlassian/amps/commits/52c38116f12475f75af4a147b7a7685478b83eca
* https://bitbucket.org/atlassian/amps/pull-requests/236
*/
2019-10-12 21:45:49 +00:00
const searchParam = "diff";
function getParamsFromSearch(search) {
2019-10-13 18:21:19 +00:00
const map = {};
2019-10-12 21:45:49 +00:00
try {
search
.split("?")[1]
.split("&")
.forEach(e => {
const values = e.split("=");
2019-10-13 18:21:19 +00:00
map[values[0]] = values[1];
2019-10-12 21:45:49 +00:00
});
} catch (_ignore) {}
2016-10-12 21:52:59 +00:00
2019-10-12 21:45:49 +00:00
return map;
}
2019-10-13 18:21:19 +00:00
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;
}
2019-10-12 21:45:49 +00:00
let fetchUrl;
const headers = new Headers();
2016-10-12 21:52:59 +00:00
2019-10-12 21:45:49 +00:00
const githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
2016-10-12 21:52:59 +00:00
2019-10-12 21:45:49 +00:00
const gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
2016-10-12 21:52:59 +00:00
2019-10-12 21:45:49 +00:00
const bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
const bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/;
2019-10-12 21:45:49 +00:00
function gitLabUrlGen(userName, projectName, type, value) {
return (
"https://crossorigin.me/https://gitlab.com/" + userName + "/" + projectName + "/" + type + "/" + value + ".diff"
);
2017-10-16 21:00:03 +00:00
}
2019-10-12 21:45:49 +00:00
function gitHubUrlGen(userName, projectName, type, value) {
headers.append("Accept", "application/vnd.github.v3.diff");
return "https://api.github.com/repos/" + userName + "/" + projectName + "/" + type + "/" + value;
2016-10-12 21:52:59 +00:00
}
2019-10-12 21:45:49 +00:00
function bitbucketUrlGen(userName, projectName, type, value) {
const baseUrl = "https://bitbucket.org/api/2.0/repositories/";
if (type === "pullrequests") {
return baseUrl + userName + "/" + projectName + "/pullrequests/" + value + "/diff";
}
return baseUrl + userName + "/" + projectName + "/diff/" + value;
}
2019-10-12 21:45:49 +00:00
let values;
if ((values = githubCommitUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], "commits", values[3]);
} else if ((values = githubPrUrl.exec(url))) {
fetchUrl = gitHubUrlGen(values[1], values[2], "pulls", values[3]);
} else if ((values = gitlabCommitUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], "commit", values[3]);
} else if ((values = gitlabPrUrl.exec(url))) {
fetchUrl = gitLabUrlGen(values[1], values[2], "merge_requests", values[3]);
} else if ((values = bitbucketCommitUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], "commit", values[3]);
} else if ((values = bitbucketPrUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], "pullrequests", values[3]);
} else {
console.info("Could not parse url, using the provided url.");
fetchUrl = "https://crossorigin.me/" + url;
}
2016-10-12 21:52:59 +00:00
2019-10-12 21:45:49 +00:00
return {
url: fetchUrl,
headers: headers
};
}
2016-10-12 21:52:59 +00:00
2019-10-13 18:21:19 +00:00
function getConfiguration(urlParams) {
// Removing `diff` form `urlParams` to avoid being inserted
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { diff, ...urlParamsRest } = urlParams;
const config = {
...global.defaultDiff2HtmlUIConfig,
...urlParamsRest
};
2016-10-12 21:52:59 +00:00
2019-10-13 18:21:19 +00:00
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 };
}, {});
2019-10-12 21:45:49 +00:00
}
2016-10-12 21:52:59 +00:00
2019-10-13 18:21:19 +00:00
function getDiff(request) {
return fetch(request.url, {
2019-10-12 21:45:49 +00:00
method: "GET",
2019-10-13 18:21:19 +00:00
headers: request.headers,
2019-10-12 21:45:49 +00:00
mode: "cors",
cache: "default"
})
2019-10-13 18:21:19 +00:00
.then(res => {
2019-10-12 21:45:49 +00:00
return res.text();
})
2019-10-13 18:21:19 +00:00
.catch(error => console.error("Failed to retrieve diff", error));
2019-10-12 21:45:49 +00:00
}
2019-10-13 18:21:19 +00:00
function draw(diffString, config, elements) {
const diff2htmlUi = new global.Diff2HtmlUI(diffString, elements.structure.diffTarget, config);
if (config.outputFormat === "side-by-side") {
elements.structure.container.style.width = "100%";
} else {
elements.structure.container.style.width = "";
}
diff2htmlUi.draw();
2019-10-12 21:45:49 +00:00
}
2019-10-13 18:21:19 +00:00
async function prepareInitialState(elements) {
const urlParams = getParamsFromSearch(window.location.search);
const currentUrl = (urlParams && urlParams[searchParam]) || "https://github.com/rtfpessoa/diff2html/pull/106";
2019-10-12 21:45:49 +00:00
2019-10-13 18:21:19 +00:00
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);
}
2019-10-12 21:45:49 +00:00
}
2019-10-13 18:21:19 +00:00
document.addEventListener("DOMContentLoaded", async () => {
2019-10-12 21:45:49 +00:00
// Improves browser compatibility
require("whatwg-fetch");
2017-10-16 21:00:03 +00:00
2019-10-13 18:21:19 +00:00
const drawAndUpdateUrl = async (diffUrl, diffString, config, elements) => {
updateBrowserUrl(config, diffUrl);
const newRequest = prepareRequest(diffUrl);
diffString = await getDiff(newRequest);
draw(diffString, config, elements);
};
2019-10-12 21:45:49 +00:00
const elements = {
2019-10-13 18:21:19 +00:00
structure: {
container: document.getElementsByClassName("container")[0],
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"),
matching: document.getElementById("diff-url-options-matching"),
wordsThreshold: document.getElementById("diff-url-options-match-words-threshold"),
matchingMaxComparisons: document.getElementById("diff-url-options-matching-max-comparisons")
},
checkboxes: {
drawFileList: document.getElementById("diff-url-options-show-files")
}
2019-10-12 21:45:49 +00:00
};
2017-10-16 21:00:03 +00:00
2019-10-13 18:21:19 +00:00
let [config, diffString] = await prepareInitialState(elements);
2019-10-13 18:21:19 +00:00
// 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;
Object.entries(elements.options).forEach(([option, element]) =>
element.addEventListener("change", () => {
config[option] = element.value;
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
})
);
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);
});
2019-10-13 18:21:19 +00:00
return drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
2016-10-12 21:52:59 +00:00
});
2019-10-12 21:45:49 +00:00
/* eslint-enable @typescript-eslint/explicit-function-return-type */