mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-10-04 15:36:50 +02:00
feat: flatten file tree for better performance
This commit is contained in:
1 parent
ccdc95e4a8
commit
710f7328e7
23 files changed
+516
-514
No files matched your search
+95
-91
@@ -270,30 +270,37 @@ angular
|
||||
});
|
||||
}
|
||||
|
||||
const toArray = function (obj) {
|
||||
const toArray = function (arr) {
|
||||
const output = [];
|
||||
for (let name in obj) {
|
||||
if (obj[name].size != null) {
|
||||
const keys = { "": { child: output } };
|
||||
for (let file of arr) {
|
||||
let current = keys[file.path].child;
|
||||
let fPath = `${file.path}/${file.name}`;
|
||||
if (fPath.startsWith("/")) {
|
||||
fPath = fPath.substring(1);
|
||||
}
|
||||
if (file.size != null) {
|
||||
// it is a file
|
||||
output.push({
|
||||
name,
|
||||
size: obj[name].size,
|
||||
sha: obj[name].sha,
|
||||
current.push({
|
||||
name: file.name,
|
||||
size: file.size,
|
||||
sha: file.sha,
|
||||
});
|
||||
} else {
|
||||
output.push({
|
||||
name,
|
||||
sha: obj[name].sha,
|
||||
child: obj[name],
|
||||
});
|
||||
const dir = {
|
||||
name: file.name,
|
||||
child: [],
|
||||
};
|
||||
keys[fPath] = dir;
|
||||
current.push(dir);
|
||||
}
|
||||
}
|
||||
return output;
|
||||
};
|
||||
|
||||
const sortFiles = (f1, f2) => {
|
||||
const f1d = isDir(f1.child);
|
||||
const f2d = isDir(f2.child);
|
||||
const f1d = !!f1.child;
|
||||
const f2d = !!f2.child;
|
||||
if (f1d && f2d) {
|
||||
return f1.name - f2.name;
|
||||
}
|
||||
@@ -307,22 +314,24 @@ angular
|
||||
};
|
||||
|
||||
function generate(current, parentPath) {
|
||||
const afiles = toArray(current).sort(sortFiles);
|
||||
if (!current) return "";
|
||||
current = current.sort(sortFiles);
|
||||
const afiles = current;
|
||||
let output = "<ul>";
|
||||
for (let f of afiles) {
|
||||
let dir = isDir(f.child);
|
||||
let dir = !!f.child;
|
||||
let name = f.name;
|
||||
let size = f.size || 0;
|
||||
if (dir) {
|
||||
let test = name;
|
||||
current = toArray(f.child);
|
||||
while (current.length == 1) {
|
||||
current = f.child;
|
||||
while (current && current.length == 1) {
|
||||
test += "/" + current[0].name;
|
||||
size = current[0].size;
|
||||
current = toArray(current[0].child);
|
||||
current = current[0].child;
|
||||
}
|
||||
name = test;
|
||||
if (current.length == 0) {
|
||||
if (size > 0) {
|
||||
dir = false;
|
||||
}
|
||||
}
|
||||
@@ -332,15 +341,27 @@ angular
|
||||
size = "";
|
||||
}
|
||||
const path = `${parentPath}/${name}`;
|
||||
output += `<li class="file ${
|
||||
dir ? "folder" : ""
|
||||
}" ng-class="{active: isActive('${path}'), open: opens['${path}']}" title="${size}">`;
|
||||
|
||||
const cssClasses = ["file"];
|
||||
if (dir) {
|
||||
cssClasses.push("folder");
|
||||
}
|
||||
if ($scope.opens[path]) {
|
||||
cssClasses.push("open");
|
||||
}
|
||||
if ($scope.isActive(path)) {
|
||||
cssClasses.push("active");
|
||||
}
|
||||
|
||||
output += `<li class="${cssClasses.join(
|
||||
" "
|
||||
)}" ng-class="{active: isActive('${path}'), open: opens['${path}']}" title="${size}">`;
|
||||
if (dir) {
|
||||
output += `<a ng-click="openFolder('${path}', $event)">${name}</a>`;
|
||||
} else {
|
||||
output += `<a href='/r/${$scope.repoId}${path}'>${name}</a>`;
|
||||
}
|
||||
if ($scope.opens[path]) {
|
||||
if ($scope.opens[path] && f.child && f.child.length > 1) {
|
||||
output += generate(f.child, parentPath + "/" + f.name);
|
||||
}
|
||||
// output += generate(f.child, parentPath + "/" + f.name);
|
||||
@@ -349,44 +370,36 @@ angular
|
||||
return output + "</ul>";
|
||||
}
|
||||
function display() {
|
||||
const output = generate($scope.file, "");
|
||||
$element.html("");
|
||||
const output = generate(toArray($scope.file).sort(sortFiles), "");
|
||||
$compile(output)($scope, (clone) => {
|
||||
$element.append(clone);
|
||||
});
|
||||
}
|
||||
|
||||
$scope.$watch("file", (newValue) => {
|
||||
if (newValue == null) return;
|
||||
if (Array.isArray(newValue)) return;
|
||||
if (Object.keys(newValue).length == 0) {
|
||||
return $element.html("Empty repository");
|
||||
}
|
||||
display();
|
||||
});
|
||||
$scope.$watch(
|
||||
"file",
|
||||
(newValue) => {
|
||||
if (newValue == null) return;
|
||||
if (newValue.length == 0) {
|
||||
return $element.html("Empty repository");
|
||||
}
|
||||
display();
|
||||
},
|
||||
true
|
||||
);
|
||||
|
||||
$scope.isActive = function (name) {
|
||||
return $routeParams.path == name.substring(1);
|
||||
};
|
||||
|
||||
$scope.openFolder = function (folder, event) {
|
||||
$scope.openFolder = async function (folder, event) {
|
||||
$scope.opens[folder] = !$scope.opens[folder];
|
||||
if (event.srcElement.nextSibling == null) {
|
||||
const folders = folder.substring(1).split("/");
|
||||
let current = $scope.file;
|
||||
for (let folder of folders) {
|
||||
current = current[folder];
|
||||
}
|
||||
$compile(generate(current, folder))($scope, (clone) => {
|
||||
angular.element(event.srcElement.parentNode).append(clone);
|
||||
});
|
||||
await $scope.$parent.getFiles(folder.substring(1));
|
||||
display();
|
||||
}
|
||||
};
|
||||
const isFile = function (child) {
|
||||
return child == null || child.size != null;
|
||||
};
|
||||
const isDir = function (child) {
|
||||
return !isFile(child);
|
||||
};
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -1177,7 +1190,7 @@ angular
|
||||
}
|
||||
await $scope.getBranches();
|
||||
} catch (error) {
|
||||
console.log("here", error);
|
||||
console.log(error);
|
||||
if (error.data) {
|
||||
$translate("ERRORS." + error.data.error).then((translation) => {
|
||||
const toast = {
|
||||
@@ -1474,6 +1487,7 @@ angular
|
||||
"$sce",
|
||||
"PDFViewerService",
|
||||
function ($scope, $http, $location, $routeParams, $sce, PDFViewerService) {
|
||||
$scope.files = [];
|
||||
const extensionModes = {
|
||||
yml: "yaml",
|
||||
txt: "text",
|
||||
@@ -1526,6 +1540,9 @@ angular
|
||||
});
|
||||
|
||||
function selectFile() {
|
||||
if ($scope.paths[0] != "") {
|
||||
return;
|
||||
}
|
||||
const readmePriority = [
|
||||
"readme.md",
|
||||
"readme.txt",
|
||||
@@ -1533,21 +1550,10 @@ angular
|
||||
"readme.1st",
|
||||
"readme",
|
||||
];
|
||||
// find current folder
|
||||
let currentFolder = $scope.files;
|
||||
for (const p of $scope.paths) {
|
||||
if (currentFolder[p]) {
|
||||
currentFolder = currentFolder[p];
|
||||
}
|
||||
}
|
||||
if (currentFolder.size && Number.isInteger(currentFolder.size)) {
|
||||
// a file is already selected
|
||||
return;
|
||||
}
|
||||
const readmeCandidates = {};
|
||||
for (const file in currentFolder) {
|
||||
if (file.toLowerCase().indexOf("readme") > -1) {
|
||||
readmeCandidates[file.toLowerCase()] = file;
|
||||
for (const file of $scope.files) {
|
||||
if (file.name.toLowerCase().indexOf("readme") > -1) {
|
||||
readmeCandidates[file.name.toLowerCase()] = file.name;
|
||||
}
|
||||
}
|
||||
let best_match = null;
|
||||
@@ -1569,36 +1575,29 @@ angular
|
||||
$location.url(uri + readmeCandidates[best_match]);
|
||||
}
|
||||
}
|
||||
function getFiles(callback) {
|
||||
$http.get(`/api/repo/${$scope.repoId}/files/`).then(
|
||||
(res) => {
|
||||
$scope.files = res.data;
|
||||
selectFile();
|
||||
if (callback) {
|
||||
return callback();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
$scope.type = "error";
|
||||
$scope.content = err.data.error;
|
||||
$scope.files = null;
|
||||
}
|
||||
);
|
||||
}
|
||||
$scope.getFiles = async function (path) {
|
||||
try {
|
||||
const res = await $http.get(
|
||||
`/api/repo/${$scope.repoId}/files/?path=${path}`
|
||||
);
|
||||
$scope.files.push(...res.data);
|
||||
return res.data;
|
||||
} catch (err) {
|
||||
$scope.type = "error";
|
||||
$scope.content = err.data.error;
|
||||
$scope.files = [];
|
||||
}
|
||||
};
|
||||
|
||||
function getSelectedFile() {
|
||||
let currentFolder = $scope.files;
|
||||
for (const p of $scope.paths) {
|
||||
if (currentFolder[p]) {
|
||||
currentFolder = currentFolder[p];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return currentFolder;
|
||||
return $scope.files.filter(
|
||||
(f) =>
|
||||
f.name == $scope.paths[$scope.paths.length - 1] &&
|
||||
f.path == $scope.paths.slice(0, $scope.paths.length - 1).join("/")
|
||||
)[0];
|
||||
}
|
||||
|
||||
async function getOptions(callback) {
|
||||
function getOptions(callback) {
|
||||
$http.get(`/api/repo/${$scope.repoId}/options`).then(
|
||||
(res) => {
|
||||
$scope.options = res.data;
|
||||
@@ -1835,8 +1834,13 @@ angular
|
||||
$scope.filePath = $routeParams.path || "";
|
||||
$scope.paths = $scope.filePath.split("/");
|
||||
|
||||
getOptions((options) => {
|
||||
getFiles(() => {
|
||||
getOptions(async (options) => {
|
||||
for (let i = 0; i < $scope.paths.length; i++) {
|
||||
const path = i > 0 ? $scope.paths.slice(0, i).join("/") : "";
|
||||
await $scope.getFiles(path);
|
||||
}
|
||||
$scope.$apply(() => {
|
||||
selectFile();
|
||||
updateContent();
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+1
-1
@@ -6,4 +6,4 @@ ${e}</blockquote>
|
||||
`}table(e,t){return"<table>\n<thead>\n"+e+"</thead>\n"+(t=t&&`<tbody>${t}</tbody>`)+"</table>\n"}tablerow(e){return`<tr>
|
||||
${e}</tr>
|
||||
`}tablecell(e,t){var i=t.header?"th":"td";return(t.align?`<${i} align="${t.align}">`:`<${i}>`)+e+`</${i}>
|
||||
`}strong(e){return`<strong>${e}</strong>`}em(e){return`<em>${e}</em>`}codespan(e){return`<code>${e}</code>`}br(){return"<br>"}del(e){return`<del>${e}</del>`}link(e,t,i){var n=c(e);if(null===n)return i;let s='<a href="'+(e=n)+'"';return t&&(s+=' title="'+t+'"'),s+=">"+i+"</a>"}image(e,t,i){var n=c(e);if(null===n)return i;let s=`<img src="${e=n}" alt="${i}"`;return t&&(s+=` title="${t}"`),s+=">"}text(e){return e}}class R{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,i){return""+i}image(e,t,i){return""+i}br(){return""}}class M{options;renderer;textRenderer;constructor(e){this.options=e||t.defaults,this.options.renderer=this.options.renderer||new E,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new R}static parse(e,t){return new M(t).parse(e)}static parseInline(e,t){return new M(t).parseInline(e)}parse(n,s=!0){let o="";for(let i=0;i<n.length;i++){var r=n[i];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const n=r,s=this.options.extensions.renderers[n.type].call({parser:this},n);if(!1!==s||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(n.type)){o+=s||"";continue}}switch(r.type){case"space":continue;case"hr":o+=this.renderer.hr();continue;case"heading":{const n=r;o+=this.renderer.heading(this.parseInline(n.tokens),n.depth,this.parseInline(n.tokens,this.textRenderer).replace(F,(e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""));continue}case"code":{const n=r;o+=this.renderer.code(n.text,n.lang,!!n.escaped);continue}case"table":{const n=r;let e="",t="";for(let e=0;e<n.header.length;e++)t+=this.renderer.tablecell(this.parseInline(n.header[e].tokens),{header:!0,align:n.align[e]});e+=this.renderer.tablerow(t);let i="";for(let e=0;e<n.rows.length;e++){const o=n.rows[e];t="";for(let e=0;e<o.length;e++)t+=this.renderer.tablecell(this.parseInline(o[e].tokens),{header:!1,align:n.align[e]});i+=this.renderer.tablerow(t)}o+=this.renderer.table(e,i);continue}case"blockquote":{const n=r,s=this.parse(n.tokens);o+=this.renderer.blockquote(s);continue}case"list":{const n=r,s=n.ordered,e=n.start,a=n.loose;let i="";for(let t=0;t<n.items.length;t++){const o=n.items[t],c=o.checked,l=o.task;let e="";if(o.task){const n=this.renderer.checkbox(!!c);a?0<o.tokens.length&&"paragraph"===o.tokens[0].type?(o.tokens[0].text=n+" "+o.tokens[0].text,o.tokens[0].tokens&&0<o.tokens[0].tokens.length&&"text"===o.tokens[0].tokens[0].type&&(o.tokens[0].tokens[0].text=n+" "+o.tokens[0].tokens[0].text)):o.tokens.unshift({type:"text",text:n+" "}):e+=n+" "}e+=this.parse(o.tokens,a),i+=this.renderer.listitem(e,l,!!c)}o+=this.renderer.list(i,s,e);continue}case"html":{const n=r;o+=this.renderer.html(n.text,n.block);continue}case"paragraph":{const n=r;o+=this.renderer.paragraph(this.parseInline(n.tokens));continue}case"text":{let e=r,t=e.tokens?this.parseInline(e.tokens):e.text;for(;i+1<n.length&&"text"===n[i+1].type;)e=n[++i],t+="\n"+(e.tokens?this.parseInline(e.tokens):e.text);o+=s?this.renderer.paragraph(t):t;continue}default:{const n='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(n),"";throw new Error(n)}}}return o}parseInline(t,i){i=i||this.renderer;let n="";for(let e=0;e<t.length;e++){var s=t[e];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[s.type]){const t=this.options.extensions.renderers[s.type].call({parser:this},s);if(!1!==t||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(s.type)){n+=t||"";continue}}switch(s.type){case"escape":{const t=s;n+=i.text(t.text);break}case"html":{const t=s;n+=i.html(t.text);break}case"link":{const t=s;n+=i.link(t.href,t.title,this.parseInline(t.tokens,i));break}case"image":{const t=s;n+=i.image(t.href,t.title,t.text);break}case"strong":{const t=s;n+=i.strong(this.parseInline(t.tokens,i));break}case"em":{const t=s;n+=i.em(this.parseInline(t.tokens,i));break}case"codespan":{const t=s;n+=i.codespan(t.text);break}case"br":n+=i.br();break;case"del":{const t=s;n+=i.del(this.parseInline(t.tokens,i));break}case"text":{const t=s;n+=i.text(t.text);break}default:{const t='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(t),"";throw new Error(t)}}}return n}}class L{options;constructor(e){this.options=e||t.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}}class ce{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#e(j.lex,M.parse);parseInline=this.#e(j.lexInline,M.parseInline);Parser=M;Renderer=E;TextRenderer=RLine truncated
|
||||
`}strong(e){return`<strong>${e}</strong>`}em(e){return`<em>${e}</em>`}codespan(e){return`<code>${e}</code>`}br(){return"<br>"}del(e){return`<del>${e}</del>`}link(e,t,i){var n=c(e);if(null===n)return i;let s='<a href="'+(e=n)+'"';return t&&(s+=' title="'+t+'"'),s+=">"+i+"</a>"}image(e,t,i){var n=c(e);if(null===n)return i;let s=`<img src="${e=n}" alt="${i}"`;return t&&(s+=` title="${t}"`),s+=">"}text(e){return e}}class R{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,i){return""+i}image(e,t,i){return""+i}br(){return""}}class M{options;renderer;textRenderer;constructor(e){this.options=e||t.defaults,this.options.renderer=this.options.renderer||new E,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new R}static parse(e,t){return new M(t).parse(e)}static parseInline(e,t){return new M(t).parseInline(e)}parse(n,s=!0){let o="";for(let i=0;i<n.length;i++){var r=n[i];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const n=r,s=this.options.extensions.renderers[n.type].call({parser:this},n);if(!1!==s||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(n.type)){o+=s||"";continue}}switch(r.type){case"space":continue;case"hr":o+=this.renderer.hr();continue;case"heading":{const n=r;o+=this.renderer.heading(this.parseInline(n.tokens),n.depth,this.parseInline(n.tokens,this.textRenderer).replace(F,(e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""));continue}case"code":{const n=r;o+=this.renderer.code(n.text,n.lang,!!n.escaped);continue}case"table":{const n=r;let e="",t="";for(let e=0;e<n.header.length;e++)t+=this.renderer.tablecell(this.parseInline(n.header[e].tokens),{header:!0,align:n.align[e]});e+=this.renderer.tablerow(t);let i="";for(let e=0;e<n.rows.length;e++){const o=n.rows[e];t="";for(let e=0;e<o.length;e++)t+=this.renderer.tablecell(this.parseInline(o[e].tokens),{header:!1,align:n.align[e]});i+=this.renderer.tablerow(t)}o+=this.renderer.table(e,i);continue}case"blockquote":{const n=r,s=this.parse(n.tokens);o+=this.renderer.blockquote(s);continue}case"list":{const n=r,s=n.ordered,e=n.start,a=n.loose;let i="";for(let t=0;t<n.items.length;t++){const o=n.items[t],c=o.checked,l=o.task;let e="";if(o.task){const n=this.renderer.checkbox(!!c);a?0<o.tokens.length&&"paragraph"===o.tokens[0].type?(o.tokens[0].text=n+" "+o.tokens[0].text,o.tokens[0].tokens&&0<o.tokens[0].tokens.length&&"text"===o.tokens[0].tokens[0].type&&(o.tokens[0].tokens[0].text=n+" "+o.tokens[0].tokens[0].text)):o.tokens.unshift({type:"text",text:n+" "}):e+=n+" "}e+=this.parse(o.tokens,a),i+=this.renderer.listitem(e,l,!!c)}o+=this.renderer.list(i,s,e);continue}case"html":{const n=r;o+=this.renderer.html(n.text,n.block);continue}case"paragraph":{const n=r;o+=this.renderer.paragraph(this.parseInline(n.tokens));continue}case"text":{let e=r,t=e.tokens?this.parseInline(e.tokens):e.text;for(;i+1<n.length&&"text"===n[i+1].type;)e=n[++i],t+="\n"+(e.tokens?this.parseInline(e.tokens):e.text);o+=s?this.renderer.paragraph(t):t;continue}default:{const n='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(n),"";throw new Error(n)}}}return o}parseInline(t,i){i=i||this.renderer;let n="";for(let e=0;e<t.length;e++){var s=t[e];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[s.type]){const t=this.options.extensions.renderers[s.type].call({parser:this},s);if(!1!==t||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(s.type)){n+=t||"";continue}}switch(s.type){case"escape":{const t=s;n+=i.text(t.text);break}case"html":{const t=s;n+=i.html(t.text);break}case"link":{const t=s;n+=i.link(t.href,t.title,this.parseInline(t.tokens,i));break}case"image":{const t=s;n+=i.image(t.href,t.title,t.text);break}case"strong":{const t=s;n+=i.strong(this.parseInline(t.tokens,i));break}case"em":{const t=s;n+=i.em(this.parseInline(t.tokens,i));break}case"codespan":{const t=s;n+=i.codespan(t.text);break}case"br":n+=i.br();break;case"del":{const t=s;n+=i.del(this.parseInline(t.tokens,i));break}case"text":{const t=s;n+=i.text(t.text);break}default:{const t='Token with "'+s.type+'" type was not found.';if(this.options.silent)return console.error(t),"";throw new Error(t)}}}return n}}class L{options;constructor(e){this.options=e||t.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}}class ce{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#e(j.lex,M.parse);parseInline=this.#e(j.lexInline,M.parseInline);Parser=M;Renderer=E;TextRenderer=RLine truncated
|
||||
Reference in new issue
Block a user