summaryrefslogtreecommitdiffstats
path: root/web_src
diff options
context:
space:
mode:
Diffstat (limited to 'web_src')
-rw-r--r--web_src/js/draw.js15
-rw-r--r--web_src/js/gitGraph.js16
-rw-r--r--web_src/js/index.js3
-rw-r--r--web_src/js/publicPath.js12
-rw-r--r--web_src/vendor/gitgraph.js/LICENSE24
-rw-r--r--web_src/vendor/gitgraph.js/gitgraph.custom.css13
-rw-r--r--web_src/vendor/gitgraph.js/gitgraph.custom.js419
7 files changed, 487 insertions, 15 deletions
diff --git a/web_src/js/draw.js b/web_src/js/draw.js
deleted file mode 100644
index bb9c7f28c7..0000000000
--- a/web_src/js/draw.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/* globals gitGraph */
-
-$(() => {
- const graphList = [];
-
- if (!document.getElementById('graph-canvas')) {
- return;
- }
-
- $('#graph-raw-list li span.node-relation').each(function () {
- graphList.push($(this).text());
- });
-
- gitGraph(document.getElementById('graph-canvas'), graphList);
-});
diff --git a/web_src/js/gitGraph.js b/web_src/js/gitGraph.js
new file mode 100644
index 0000000000..cfa466d8c8
--- /dev/null
+++ b/web_src/js/gitGraph.js
@@ -0,0 +1,16 @@
+$(async () => {
+ const graphCanvas = document.getElementById('graph-canvas');
+ if (!graphCanvas) return;
+
+ const [{ default: gitGraph }] = await Promise.all([
+ import(/* webpackChunkName: "gitgraph" */'../vendor/gitgraph.js/gitgraph.custom.js'),
+ import(/* webpackChunkName: "gitgraph" */'../vendor/gitgraph.js/gitgraph.custom.css'),
+ ]);
+
+ const graphList = [];
+ $('#graph-raw-list li span.node-relation').each(function () {
+ graphList.push($(this).text());
+ });
+
+ gitGraph(graphCanvas, graphList);
+});
diff --git a/web_src/js/index.js b/web_src/js/index.js
index 704647d9c4..671c66f689 100644
--- a/web_src/js/index.js
+++ b/web_src/js/index.js
@@ -2,6 +2,9 @@
/* exported timeAddManual, toggleStopwatch, cancelStopwatch, initHeatmap */
/* exported toggleDeadlineForm, setDeadline, updateDeadline, deleteDependencyModal, cancelCodeComment, onOAuthLoginClick */
+import './publicPath';
+import './gitGraph';
+
function htmlEncode(text) {
return jQuery('<div />').text(text).html();
}
diff --git a/web_src/js/publicPath.js b/web_src/js/publicPath.js
new file mode 100644
index 0000000000..5d277e442a
--- /dev/null
+++ b/web_src/js/publicPath.js
@@ -0,0 +1,12 @@
+/* This sets up webpack's chunk loading to load resources from the same
+ directory where it loaded index.js from. This file must be imported
+ before any lazy-loading is being attempted. */
+
+if (document.currentScript && document.currentScript.src) {
+ const url = new URL(document.currentScript.src);
+ __webpack_public_path__ = `${url.pathname.replace(/\/[^/]*$/, '')}/`;
+} else {
+ // compat: IE11
+ const script = document.querySelector('script[src*="/index.js"]');
+ __webpack_public_path__ = `${script.getAttribute('src').replace(/\/[^/]*$/, '')}/`;
+}
diff --git a/web_src/vendor/gitgraph.js/LICENSE b/web_src/vendor/gitgraph.js/LICENSE
new file mode 100644
index 0000000000..30cd6b7692
--- /dev/null
+++ b/web_src/vendor/gitgraph.js/LICENSE
@@ -0,0 +1,24 @@
+Copyright (c) 2011, Terrence Lee <kill889@gmail.com>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the fgdev nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file
diff --git a/web_src/vendor/gitgraph.js/gitgraph.custom.css b/web_src/vendor/gitgraph.js/gitgraph.custom.css
new file mode 100644
index 0000000000..92d2dcc20d
--- /dev/null
+++ b/web_src/vendor/gitgraph.js/gitgraph.custom.css
@@ -0,0 +1,13 @@
+#git-graph-container, #rel-container {float:left;}
+#rel-container {max-width:30%; overflow-x:auto;}
+#git-graph-container {overflow-x:auto; width:100%}
+#git-graph-container li {list-style-type:none;height:20px;line-height:20px; white-space:nowrap;}
+#git-graph-container li .node-relation {font-family:'Bitstream Vera Sans Mono', 'Courier', monospace;}
+#git-graph-container li .author {color:#666666;}
+#git-graph-container li .time {color:#999999;font-size:80%}
+#git-graph-container li a {color:#000000;}
+#git-graph-container li a:hover {text-decoration:underline;}
+#git-graph-container li a em {color:#BB0000;border-bottom:1px dotted #BBBBBB;text-decoration:none;font-style:normal;}
+#rev-container {width:100%}
+#rev-list {margin:0;padding:0 5px 0 5px;min-width:95%}
+#graph-raw-list {margin:0px;}
diff --git a/web_src/vendor/gitgraph.js/gitgraph.custom.js b/web_src/vendor/gitgraph.js/gitgraph.custom.js
new file mode 100644
index 0000000000..2c18a2d03e
--- /dev/null
+++ b/web_src/vendor/gitgraph.js/gitgraph.custom.js
@@ -0,0 +1,419 @@
+/*
+ * @license magnet:?xt=urn:btih:c80d50af7d3db9be66a4d0a86db0286e4fd33292&dn=bsd-3-clause.txt BSD 3-Clause
+ * Copyright (c) 2011, Terrence Lee <kill889@gmail.com>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the <organization> nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+export default function gitGraph(canvas, rawGraphList, config) {
+ if (!canvas.getContext) {
+ return;
+ }
+
+ if (typeof config === 'undefined') {
+ config = {
+ unitSize: 20,
+ lineWidth: 3,
+ nodeRadius: 4
+ };
+ }
+
+ const flows = [];
+ const graphList = [];
+
+ const ctx = canvas.getContext('2d');
+
+ const devicePixelRatio = window.devicePixelRatio || 1;
+ const backingStoreRatio = ctx.webkitBackingStorePixelRatio
+ || ctx.mozBackingStorePixelRatio
+ || ctx.msBackingStorePixelRatio
+ || ctx.oBackingStorePixelRatio
+ || ctx.backingStorePixelRatio || 1;
+
+ const ratio = devicePixelRatio / backingStoreRatio;
+
+ const init = function () {
+ let maxWidth = 0;
+ let i;
+ const l = rawGraphList.length;
+ let row;
+ let midStr;
+
+ for (i = 0; i < l; i++) {
+ midStr = rawGraphList[i].replace(/\s+/g, ' ').replace(/^\s+|\s+$/g, '');
+
+ maxWidth = Math.max(midStr.replace(/(_|\s)/g, '').length, maxWidth);
+
+ row = midStr.split('');
+
+ graphList.unshift(row);
+ }
+
+ const width = maxWidth * config.unitSize;
+ const height = graphList.length * config.unitSize;
+
+ canvas.width = width * ratio;
+ canvas.height = height * ratio;
+
+ canvas.style.width = `${width}px`;
+ canvas.style.height = `${height}px`;
+
+ ctx.lineWidth = config.lineWidth;
+ ctx.lineJoin = 'round';
+ ctx.lineCap = 'round';
+
+ ctx.scale(ratio, ratio);
+ };
+
+ const genRandomStr = function () {
+ const chars = '0123456789ABCDEF';
+ const stringLength = 6;
+ let randomString = '', rnum, i;
+ for (i = 0; i < stringLength; i++) {
+ rnum = Math.floor(Math.random() * chars.length);
+ randomString += chars.substring(rnum, rnum + 1);
+ }
+
+ return randomString;
+ };
+
+ const findFlow = function (id) {
+ let i = flows.length;
+
+ while (i-- && flows[i].id !== id);
+
+ return i;
+ };
+
+ const findColomn = function (symbol, row) {
+ let i = row.length;
+
+ while (i-- && row[i] !== symbol);
+
+ return i;
+ };
+
+ const findBranchOut = function (row) {
+ if (!row) {
+ return -1;
+ }
+
+ let i = row.length;
+
+ while (i--
+ && !(row[i - 1] && row[i] === '/' && row[i - 1] === '|')
+ && !(row[i - 2] && row[i] === '_' && row[i - 2] === '|'));
+
+ return i;
+ };
+
+ const findLineBreak = function (row) {
+ if (!row) {
+ return -1;
+ }
+
+ let i = row.length;
+
+ while (i--
+ && !(row[i - 1] && row[i - 2] && row[i] === ' ' && row[i - 1] === '|' && row[i - 2] === '_'));
+
+ return i;
+ };
+
+ const genNewFlow = function () {
+ let newId;
+
+ do {
+ newId = genRandomStr();
+ } while (findFlow(newId) !== -1);
+
+ return { id: newId, color: `#${newId}` };
+ };
+
+ // Draw methods
+ const drawLine = function (moveX, moveY, lineX, lineY, color) {
+ ctx.strokeStyle = color;
+ ctx.beginPath();
+ ctx.moveTo(moveX, moveY);
+ ctx.lineTo(lineX, lineY);
+ ctx.stroke();
+ };
+
+ const drawLineRight = function (x, y, color) {
+ drawLine(x, y + config.unitSize / 2, x + config.unitSize, y + config.unitSize / 2, color);
+ };
+
+ const drawLineUp = function (x, y, color) {
+ drawLine(x, y + config.unitSize / 2, x, y - config.unitSize / 2, color);
+ };
+
+ const drawNode = function (x, y, color) {
+ ctx.strokeStyle = color;
+
+ drawLineUp(x, y, color);
+
+ ctx.beginPath();
+ ctx.arc(x, y, config.nodeRadius, 0, Math.PI * 2, true);
+ ctx.fill();
+ };
+
+ const drawLineIn = function (x, y, color) {
+ drawLine(x + config.unitSize, y + config.unitSize / 2, x, y - config.unitSize / 2, color);
+ };
+
+ const drawLineOut = function (x, y, color) {
+ drawLine(x, y + config.unitSize / 2, x + config.unitSize, y - config.unitSize / 2, color);
+ };
+
+ const draw = function (graphList) {
+ let colomn, colomnIndex, prevColomn, condenseIndex, breakIndex = -1;
+ let x, y;
+ let color;
+ let nodePos;
+ let tempFlow;
+ let prevRowLength = 0;
+ let flowSwapPos = -1;
+ let lastLinePos;
+ let i, l;
+ let condenseCurrentLength, condensePrevLength = 0;
+
+ let inlineIntersect = false;
+
+ // initiate color array for first row
+ for (i = 0, l = graphList[0].length; i < l; i++) {
+ if (graphList[0][i] !== '_' && graphList[0][i] !== ' ') {
+ flows.push(genNewFlow());
+ }
+ }
+
+ y = (canvas.height / ratio) - config.unitSize * 0.5;
+
+ // iterate
+ for (i = 0, l = graphList.length; i < l; i++) {
+ x = config.unitSize * 0.5;
+
+ const currentRow = graphList[i];
+ const nextRow = graphList[i + 1];
+ const prevRow = graphList[i - 1];
+
+ flowSwapPos = -1;
+
+ condenseCurrentLength = currentRow.filter((val) => {
+ return (val !== ' ' && val !== '_');
+ }).length;
+
+ // pre process begin
+ // use last row for analysing
+ if (prevRow) {
+ if (!inlineIntersect) {
+ // intersect might happen
+ for (colomnIndex = 0; colomnIndex < prevRowLength; colomnIndex++) {
+ if (prevRow[colomnIndex + 1]
+ && (prevRow[colomnIndex] === '/' && prevRow[colomnIndex + 1] === '|')
+ || ((prevRow[colomnIndex] === '_' && prevRow[colomnIndex + 1] === '|')
+ && (prevRow[colomnIndex + 2] === '/'))) {
+ flowSwapPos = colomnIndex;
+
+ // swap two flow
+ tempFlow = { id: flows[flowSwapPos].id, color: flows[flowSwapPos].color };
+
+ flows[flowSwapPos].id = flows[flowSwapPos + 1].id;
+ flows[flowSwapPos].color = flows[flowSwapPos + 1].color;
+
+ flows[flowSwapPos + 1].id = tempFlow.id;
+ flows[flowSwapPos + 1].color = tempFlow.color;
+ }
+ }
+ }
+
+ if (condensePrevLength < condenseCurrentLength
+ && ((nodePos = findColomn('*', currentRow)) !== -1
+ && (findColomn('_', currentRow) === -1))) {
+ flows.splice(nodePos - 1, 0, genNewFlow());
+ }
+
+ if (prevRowLength > currentRow.length
+ && (nodePos = findColomn('*', prevRow)) !== -1) {
+ if (findColomn('_', currentRow) === -1
+ && findColomn('/', currentRow) === -1
+ && findColomn('\\', currentRow) === -1) {
+ flows.splice(nodePos + 1, 1);
+ }
+ }
+ } // done with the previous row
+
+ prevRowLength = currentRow.length; // store for next round
+ colomnIndex = 0; // reset index
+ condenseIndex = 0;
+ condensePrevLength = 0;
+ breakIndex = -1; // reset break index
+ while (colomnIndex < currentRow.length) {
+ colomn = currentRow[colomnIndex];
+
+ if (colomn !== ' ' && colomn !== '_') {
+ ++condensePrevLength;
+ }
+
+ // check and fix line break in next row
+ if (colomn === '/' && currentRow[colomnIndex - 1] && currentRow[colomnIndex - 1] === '|') {
+ if ((breakIndex = findLineBreak(nextRow)) !== -1) {
+ nextRow.splice(breakIndex, 1);
+ }
+ }
+ // if line break found replace all '/' with '|' after breakIndex in previous row
+ if (breakIndex !== -1 && colomn === '/' && colomnIndex > breakIndex) {
+ currentRow[colomnIndex] = '|';
+ colomn = '|';
+ }
+
+ if (colomn === ' '
+ && currentRow[colomnIndex + 1]
+ && currentRow[colomnIndex + 1] === '_'
+ && currentRow[colomnIndex - 1]
+ && currentRow[colomnIndex - 1] === '|') {
+ currentRow.splice(colomnIndex, 1);
+
+ currentRow[colomnIndex] = '/';
+ colomn = '/';
+ }
+
+ // create new flow only when no intersect happened
+ if (flowSwapPos === -1
+ && colomn === '/'
+ && currentRow[colomnIndex - 1]
+ && currentRow[colomnIndex - 1] === '|') {
+ flows.splice(condenseIndex, 0, genNewFlow());
+ }
+
+ // change \ and / to | when it's in the last position of the whole row
+ if (colomn === '/' || colomn === '\\') {
+ if (!(colomn === '/' && findBranchOut(nextRow) === -1)) {
+ if ((lastLinePos = Math.max(findColomn('|', currentRow),
+ findColomn('*', currentRow))) !== -1
+ && (lastLinePos < colomnIndex - 1)) {
+ while (currentRow[++lastLinePos] === ' ');
+
+ if (lastLinePos === colomnIndex) {
+ currentRow[colomnIndex] = '|';
+ }
+ }
+ }
+ }
+
+ if (colomn === '*'
+ && prevRow
+ && prevRow[condenseIndex + 1] === '\\') {
+ flows.splice(condenseIndex + 1, 1);
+ }
+
+ if (colomn !== ' ') {
+ ++condenseIndex;
+ }
+
+ ++colomnIndex;
+ }
+
+ condenseCurrentLength = currentRow.filter((val) => {
+ return (val !== ' ' && val !== '_');
+ }).length;
+
+ // do some clean up
+ if (flows.length > condenseCurrentLength) {
+ flows.splice(condenseCurrentLength, flows.length - condenseCurrentLength);
+ }
+
+ colomnIndex = 0;
+
+ // a little inline analysis and draw process
+ while (colomnIndex < currentRow.length) {
+ colomn = currentRow[colomnIndex];
+ prevColomn = currentRow[colomnIndex - 1];
+
+ if (currentRow[colomnIndex] === ' ') {
+ currentRow.splice(colomnIndex, 1);
+ x += config.unitSize;
+
+ continue;
+ }
+
+ // inline interset
+ if ((colomn === '_' || colomn === '/')
+ && currentRow[colomnIndex - 1] === '|'
+ && currentRow[colomnIndex - 2] === '_') {
+ inlineIntersect = true;
+
+ tempFlow = flows.splice(colomnIndex - 2, 1)[0];
+ flows.splice(colomnIndex - 1, 0, tempFlow);
+ currentRow.splice(colomnIndex - 2, 1);
+
+ colomnIndex -= 1;
+ } else {
+ inlineIntersect = false;
+ }
+
+ color = flows[colomnIndex].color;
+
+ switch (colomn) {
+ case '_':
+ drawLineRight(x, y, color);
+
+ x += config.unitSize;
+ break;
+
+ case '*':
+ drawNode(x, y, color);
+ break;
+
+ case '|':
+ drawLineUp(x, y, color);
+ break;
+
+ case '/':
+ if (prevColomn
+ && (prevColomn === '/'
+ || prevColomn === ' ')) {
+ x -= config.unitSize;
+ }
+
+ drawLineOut(x, y, color);
+
+ x += config.unitSize;
+ break;
+
+ case '\\':
+ drawLineIn(x, y, color);
+ break;
+ }
+
+ ++colomnIndex;
+ }
+
+ y -= config.unitSize;
+ }
+ };
+
+ init();
+ draw(graphList);
+}
+// @end-license