Skip to content

Commit

Permalink
Added search engine
Browse files Browse the repository at this point in the history
  • Loading branch information
Rackover committed Mar 6, 2021
1 parent 105bb1f commit 14d9f0d
Show file tree
Hide file tree
Showing 10 changed files with 183 additions and 12 deletions.
1 change: 1 addition & 0 deletions app.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ global.wikiMap = require("./app/map.js")
global.wikiPage = require("./app/page.js")
global.wikiContents = require('./app/content.js')
global.utility = require("./app/utility.js")
global.searchEngine = require("./app/search.js");

logger.debug(`Running in directory ${EXECUTION_ROOT} with application root ${APPLICATION_ROOT} and wiki path: ${WIKI_PATH}`)
logger.debug("Parchment currently running as OS user: "+require('os').userInfo().username)
Expand Down
1 change: 1 addition & 0 deletions app/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ module.exports = function(port){
const routes = [
{name:"read/*", isProtected: false},
{name:"write/*", isProtected: true},
{name:"search", isProtected: false}
]

// All routes
Expand Down
7 changes: 7 additions & 0 deletions app/layout/default.pug
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ html
title #{website.name}
link(rel="stylesheet", href="/res/css/font-awesome-all.css")
link(rel="stylesheet", href="/res/css/highlight-js.min.css")
script(src="/res/js/jquery.min.js")
block head
link(rel="stylesheet", href=website.links.css)
link(rel="icon", type="image/png", href=website.links.favicon)
Expand All @@ -48,6 +49,12 @@ html
label(for="pass") Pass
input(type="password", name="pass")
input(type="submit", value="🡆")


form.searchBar(method="GET", action="/search")
input(type="text", name="term", placeholder="Search...")
input(type="submit", value="🔍")

include elements/header.pug
.mainContainer
.navigation
Expand Down
7 changes: 5 additions & 2 deletions app/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async function updateTree(){
if (isOperating) await new Promise(resolve => bus.once('unlocked', resolve));
isOperating = true;

tree = await scanDirectory( WIKI_PATH)
tree = await scanDirectory(WIKI_PATH)

isOperating = false;
bus.emit('unlocked');
Expand All @@ -40,6 +40,7 @@ async function scanDirectory(dirPath){
const fullPath = fullPathNoExt+".md";
const contents = await readFile(fullPath)
const virtualPath = fullPath.replace(WIKI_PATH, "");
const meta = markdown.parseMeta(contents.toString());

entries[virtualPath] = {
url: virtualPath,
Expand All @@ -53,11 +54,13 @@ async function scanDirectory(dirPath){
.replace(".git", "/blob/"+process.env.GIT_REPO_BRANCH)
+ "/"
+ virtualPath,
name: markdown.parseMeta(contents.toString()).title || name,
name: meta.title || name,
children: fs.existsSync(fullPathNoExt) ? await scanDirectory(fullPathNoExt) : false
}

pages[virtualPath] = entries[virtualPath]
searchEngine.updateIndexForPageIfNecessary(virtualPath, entries[virtualPath].name, contents.toString());

logger.debug("Added "+cleanName+" to "+virtualPath)
}
return entries
Expand Down
9 changes: 6 additions & 3 deletions app/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ async function addPage(virtualPath, contents){
const fileName = elems[elems.length-1]
logger.info("Adding page "+fileName+"...")
mkdirp.sync(diskPath.substring(0, diskPath.lastIndexOf('/')))

await writeFile(diskPath, contents)

await writeFile(diskPath, contents);
searchEngine.updateIndexForPage(virtualPath, markdown.parseMeta(contents).title, contents);

// This will update tree
await git.checkAndUploadModifications("Updated "+fileName)
Expand All @@ -54,7 +55,9 @@ async function destroyPage(virtualPath){
const fileName = elems[elems.length-1]
logger.info("Destroying page "+fileName+"...")

const mdPath = path.join(EXECUTION_ROOT, diskPath)
searchEngine.removePageFromIndex(virtualPath);

const mdPath = diskPath;
const dirPath = mdPath.substring(0, mdPath.length-3);

if (fs.existsSync(dirPath)){
Expand Down
42 changes: 42 additions & 0 deletions app/routes/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const maxSummaryLength = 40;
const backwardLength = 8;

module.exports = async function (req, response){

const body = req.query;
const miss = utility.getMissingFields(body, ["term"])

if (miss.length > 0 || body.term.length <= 0){
response.error = {
data: 'No search term was given'
};

return response;
}

const results = await searchEngine.search(body.term);

for (i in results){
let wholePage = results[i].content;
let summary = wholePage
.slice(Math.max(0, results[i].position-backwardLength));

const originalLength = summary.length;

summary = summary
.slice(0, Math.min(maxSummaryLength, summary.length))
.join(" ");

if (summary.length < originalLength){
summary += "...";
}

results[i].summary = summary;
}

response.searchTerm = body.term;
response.results = results;

return response;
}

90 changes: 90 additions & 0 deletions app/search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@

const minWordLength = 4;
let index = {};

module.exports = {
updateIndexForPage: updateIndexForPage,
updateIndexForPageIfNecessary: updateIndexForPageIfNecessary,
removePageFromIndex: removePageFromIndex,
search: search
}

async function updateIndexForPageIfNecessary(virtualPath, title, content){
if (index[virtualPath] == undefined || index[virtualPath].length != content.length){
logger.debug(`Updating search index for virtual path ${virtualPath}`);
await updateIndexForPage(virtualPath, title, content);
}
}

async function updateIndexForPage(virtualPath, title, content){
if (index[virtualPath] != undefined){
removePageFromIndex(virtualPath);
}

let entry = {
length: content.length,
title: title,
words: []
};

let pageWords = content
.replace(/[^A-Za-zÀ-ÖØ-öø-ÿ ]/gi, '')
.split(" ")
.filter((o) => o.length >= minWordLength)
.map((o) => o.toLowerCase());

entry.words = pageWords;

index[virtualPath] = entry;
}

function removePageFromIndex(virtualPath){
logger.debug(`Removing search index for virtual path ${virtualPath}`);
delete index[virtualPath];
}

function search(term){
const microtime = (Date.now() % 1000) / 1000;
logger.info(`Searching for term [${term}] in the index...`);

return new Promise((resolve, reject) => {
term = term.toLowerCase();
let results = [];
for (path in index){
if (index[path].title.includes(term)){

results.push({
virtualPath: path,
title: index[path].title,
content: index[path].words,
position: 0
});

continue;
}

for(i in index[path].words){
const word = index[path].words[i];

if (word.length < term.length){
continue;
}

if (word.includes(term)){
results.push({
virtualPath: path,
title: index[path].title,
content: index[path].words
.map((o)=>{ return o == word ? `<b>${word}</b>` : o; }),
position: i
});

break;
}
}
}

logger.info(`Found ${results.length} for search [${term}] after ${((Date.now() % 1000) / 1000) - microtime}ms`);
resolve(results);
});
}
1 change: 0 additions & 1 deletion app/views/read.pug
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ mixin create_toc(tree, depth=0)
+create_toc(anchor.nodes, depth+1)

block head
script(src="/res/js/jquery.min.js")
script(src="/res/js/loginForm.js")

block content
Expand Down
11 changes: 11 additions & 0 deletions app/views/search.pug
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
extends ../layout/default.pug

block head
script(src="/res/js/loginForm.js")

block content
h1 Results for "#{searchTerm}"
each result in results
h2
a(href="/read/"+result.virtualPath) #{result.title}
p !{result.summary}
26 changes: 20 additions & 6 deletions public/res/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -57,31 +57,45 @@ body{
mix-blend-mode: difference;
}

.header .userBar{
.header .userBar, .header .searchBar{
font-style:italic;
color:LIGHT;
position:absolute;
right:20PX;
BOTTOM:0;
TOP:0;
margin:6px;
text-align:right;
}

.header .userBar input{
.header .searchBar{
top: auto;
bottom:0;
}

.header input{
width:120px;
margin-left:10px;
margin-right:10px;
background:rgba(0,0,0,0.4);
border:1px solid LIGHTEST;
border:1px solid DARK;
color: LIGHT;
font-family: inherit;
padding-left:4px;
}

.header .userBar input[type=submit]{
.header .searchBar input{
width:10vw;
border:1px solid LIGHTEST;
}

.header input[type=submit]{
padding-left:10px;
padding-right:10px;
width:min-content;
width:40px;
}

.header input[type=submit][name="logout"]{
width:6vw;
}

.header #loginError{
Expand Down

0 comments on commit 14d9f0d

Please sign in to comment.