mirror of
https://github.com/simon987/Simple-Incremental-Search-Tool.git
synced 2025-04-10 14:06:41 +00:00
595 lines
18 KiB
JavaScript
595 lines
18 KiB
JavaScript
let searchBar = document.getElementById("searchBar");
|
|
let pathBar = document.getElementById("pathBar");
|
|
let scroll_id = null;
|
|
let docCount = 0;
|
|
let searchQueued = false;
|
|
let coolingDown = false;
|
|
let selectedDirs = [];
|
|
|
|
function toggleSearchBar() {
|
|
searchQueued = true;
|
|
}
|
|
|
|
let tree = new InspireTree({
|
|
selection: {
|
|
mode: 'checkbox'
|
|
},
|
|
data: mimeMap
|
|
});
|
|
new InspireTreeDOM(tree, {
|
|
target: '.tree'
|
|
});
|
|
|
|
//Select all
|
|
tree.select();
|
|
tree.node("any").deselect();
|
|
|
|
tree.on("node.click", function(event, node, handler) {
|
|
event.preventTreeDefault();
|
|
|
|
if (node.id === "any") {
|
|
|
|
if (!node.itree.state.checked) {
|
|
tree.deselect();
|
|
}
|
|
} else {
|
|
tree.node("any").deselect();
|
|
}
|
|
|
|
handler();
|
|
searchQueued = true;
|
|
});
|
|
|
|
new autoComplete({
|
|
selector: '#pathBar',
|
|
minChars: 1,
|
|
delay: 75,
|
|
renderItem: function (item){
|
|
return '<div class="autocomplete-suggestion" data-val="' + item + '">' + item + '</div>';
|
|
},
|
|
source: async function(term, suggest) {
|
|
term = term.toLowerCase();
|
|
|
|
const choices = await getPathChoices();
|
|
|
|
let matches = [];
|
|
for (let i=0; i<choices.length; i++) {
|
|
if (~choices[i].toLowerCase().indexOf(term)) {
|
|
matches.push(choices[i]);
|
|
}
|
|
}
|
|
suggest(matches);
|
|
},
|
|
onSelect: function() {
|
|
searchQueued = true;
|
|
}
|
|
});
|
|
|
|
function makeStatsCard(searchResult) {
|
|
|
|
let statsCard = document.createElement("div");
|
|
statsCard.setAttribute("class", "card");
|
|
let statsCardBody = document.createElement("div");
|
|
statsCardBody.setAttribute("class", "card-body");
|
|
|
|
let stat = document.createElement("p");
|
|
stat.appendChild(document.createTextNode(searchResult["hits"]["total"] + " results in " + searchResult["took"] + "ms"));
|
|
|
|
let sizeStat = document.createElement("span");
|
|
sizeStat.appendChild(document.createTextNode(humanFileSize(searchResult["aggregations"]["total_size"]["value"])));
|
|
|
|
statsCardBody.appendChild(stat);
|
|
statsCardBody.appendChild(sizeStat);
|
|
statsCard.appendChild(statsCardBody);
|
|
|
|
return statsCard;
|
|
}
|
|
|
|
function makeResultContainer() {
|
|
let resultContainer = document.createElement("div");
|
|
resultContainer.setAttribute("class", "card-columns");
|
|
|
|
return resultContainer;
|
|
}
|
|
|
|
/**
|
|
* https://stackoverflow.com/questions/10420352
|
|
*/
|
|
function humanFileSize(bytes) {
|
|
|
|
if(bytes === 0) {
|
|
return "? B"
|
|
}
|
|
|
|
let thresh = 1000;
|
|
if(Math.abs(bytes) < thresh) {
|
|
return bytes + ' B';
|
|
}
|
|
let units = ['kB','MB','GB','TB','PB','EB','ZB','YB'];
|
|
let u = -1;
|
|
do {
|
|
bytes /= thresh;
|
|
++u;
|
|
} while(Math.abs(bytes) >= thresh && u < units.length - 1);
|
|
|
|
return bytes.toFixed(1) + ' ' + units[u];
|
|
}
|
|
|
|
/**
|
|
* https://stackoverflow.com/questions/6312993
|
|
*/
|
|
function humanTime (sec_num) {
|
|
sec_num = Math.floor(sec_num);
|
|
let hours = Math.floor(sec_num / 3600);
|
|
let minutes = Math.floor((sec_num - (hours * 3600)) / 60);
|
|
let seconds = sec_num - (hours * 3600) - (minutes * 60);
|
|
|
|
if (hours < 10) {hours = "0" + hours;}
|
|
if (minutes < 10) {minutes = "0" + minutes;}
|
|
if (seconds < 10) {seconds = "0" + seconds;}
|
|
return hours + ":" + minutes + ":" + seconds;
|
|
}
|
|
|
|
|
|
function initPopover() {
|
|
$('[data-toggle="popover"]').popover({
|
|
trigger: "focus",
|
|
delay: { "show": 0, "hide": 100 },
|
|
placement: "bottom",
|
|
html: true
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Enable gif loading on hover
|
|
* @param thumbnail
|
|
* @param documentId
|
|
*/
|
|
function gifOver(thumbnail, documentId) {
|
|
let callee = arguments.callee;
|
|
|
|
thumbnail.addEventListener("mouseover", function () {
|
|
|
|
thumbnail.mouseStayedOver = true;
|
|
|
|
window.setTimeout(function() {
|
|
if (thumbnail.mouseStayedOver) {
|
|
thumbnail.removeEventListener('mouseover', callee, false);
|
|
|
|
//Load gif
|
|
thumbnail.setAttribute("src", "/file/" + documentId);
|
|
}
|
|
}, 750);
|
|
|
|
});
|
|
|
|
thumbnail.addEventListener("mouseout", function() {
|
|
//Reset timer
|
|
thumbnail.mouseStayedOver = false;
|
|
thumbnail.setAttribute("src", "/thumb/" + documentId);
|
|
|
|
})
|
|
}
|
|
|
|
function downloadPopover(element, documentId) {
|
|
element.setAttribute("data-content",
|
|
'<a class="btn btn-sm btn-primary" href="/dl/'+ documentId +'"><i class="fas fa-download"></i> Télécharger</a>' +
|
|
'<a class="btn btn-sm btn-success" style="margin-left:3px;" href="/file/'+ documentId + '" target="_blank"><i class="fas fa-eye"></i> Consulter</a>');
|
|
element.setAttribute("data-toggle", "popover");
|
|
element.addEventListener("mouseover", function() {
|
|
element.focus();
|
|
});
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param hit
|
|
* @returns {Element}
|
|
*/
|
|
function createDocCard(hit) {
|
|
|
|
let docCard = document.createElement("div");
|
|
docCard.setAttribute("class", "card");
|
|
docCard.setAttribute("tabindex", "-1");
|
|
|
|
let docCardBody = document.createElement("div");
|
|
docCardBody.setAttribute("class", "card-body document");
|
|
|
|
let link = document.createElement("a");
|
|
link.setAttribute("href", "/document/" + hit["_id"]);
|
|
link.setAttribute("target", "_blank");
|
|
|
|
//Title
|
|
let title = document.createElement("p");
|
|
title.setAttribute("class", "file-title");
|
|
let extension = hit["_source"].hasOwnProperty("extension") && hit["_source"]["extension"] !== "" ? "." + hit["_source"]["extension"] : "";
|
|
|
|
if (hit.hasOwnProperty("highlight") && hit["highlight"].hasOwnProperty("name")) {
|
|
title.insertAdjacentHTML('afterbegin', hit["highlight"]["name"] + extension);
|
|
} else {
|
|
title.appendChild(document.createTextNode(hit["_source"]["name"] + extension));
|
|
}
|
|
|
|
title.setAttribute("title", hit["_source"]["path"] + hit["_source"]["name"] + extension);
|
|
docCard.appendChild(title);
|
|
|
|
let tagContainer = document.createElement("div");
|
|
tagContainer.setAttribute("class", "card-text");
|
|
|
|
if (hit["_source"].hasOwnProperty("mime") && hit["_source"]["mime"] !== null) {
|
|
|
|
let tags = [];
|
|
let thumbnail = null;
|
|
let thumbnailOverlay = null;
|
|
let imgWrapper = document.createElement("div");
|
|
imgWrapper.setAttribute("style", "position: relative");
|
|
|
|
let mimeCategory = hit["_source"]["mime"].split("/")[0];
|
|
|
|
//Thumbnail
|
|
switch (mimeCategory) {
|
|
|
|
case "video":
|
|
thumbnail = document.createElement("video");
|
|
let vidSource = document.createElement("source");
|
|
vidSource.setAttribute("src", "/file/" + hit["_id"]);
|
|
vidSource.setAttribute("type", "video/webm");
|
|
thumbnail.appendChild(vidSource);
|
|
thumbnail.setAttribute("class", "fit");
|
|
thumbnail.setAttribute("loop", "");
|
|
thumbnail.setAttribute("controls", "");
|
|
thumbnail.setAttribute("preload", "none");
|
|
thumbnail.setAttribute("poster", "/thumb/" + hit["_id"]);
|
|
thumbnail.addEventListener("dblclick", function() {
|
|
thumbnail.webkitRequestFullScreen();
|
|
});
|
|
|
|
break;
|
|
case "image":
|
|
thumbnail = document.createElement("img");
|
|
thumbnail.setAttribute("class", "card-img-top fit");
|
|
thumbnail.setAttribute("src", "/thumb/" + hit["_id"]);
|
|
break;
|
|
}
|
|
|
|
//Thumbnail overlay
|
|
switch (mimeCategory) {
|
|
|
|
case "image":
|
|
thumbnailOverlay = document.createElement("div");
|
|
thumbnailOverlay.setAttribute("class", "card-img-overlay");
|
|
|
|
//Resolution
|
|
let resolutionBadge = document.createElement("span");
|
|
resolutionBadge.setAttribute("class", "badge badge-resolution");
|
|
if (hit["_source"].hasOwnProperty("width")) {
|
|
resolutionBadge.appendChild(document.createTextNode(hit["_source"]["width"] + "x" + hit["_source"]["height"]));
|
|
}
|
|
thumbnailOverlay.appendChild(resolutionBadge);
|
|
|
|
var format = hit["_source"]["format"];
|
|
|
|
//Hover
|
|
if(format === "GIF") {
|
|
gifOver(thumbnail, hit["_id"]);
|
|
}
|
|
break;
|
|
|
|
case "video":
|
|
//Duration
|
|
if (hit["_source"].hasOwnProperty("duration")) {
|
|
thumbnailOverlay = document.createElement("div");
|
|
thumbnailOverlay.setAttribute("class", "card-img-overlay");
|
|
let durationBadge = document.createElement("span");
|
|
durationBadge.setAttribute("class", "badge badge-resolution");
|
|
durationBadge.appendChild(document.createTextNode(humanTime(hit["_source"]["duration"])));
|
|
thumbnailOverlay.appendChild(durationBadge);
|
|
}
|
|
}
|
|
|
|
//Tags
|
|
switch (mimeCategory) {
|
|
|
|
case "video":
|
|
if (hit["_source"].hasOwnProperty("format_long_name")) {
|
|
let formatTag = document.createElement("span");
|
|
formatTag.setAttribute("class", "badge badge-pill badge-video");
|
|
formatTag.appendChild(document.createTextNode(hit["_source"]["format_long_name"].replace(" ", "")));
|
|
tags.push(formatTag);
|
|
}
|
|
|
|
break;
|
|
case "image": {
|
|
let formatTag = document.createElement("span");
|
|
formatTag.setAttribute("class", "badge badge-pill badge-image");
|
|
formatTag.appendChild(document.createTextNode(format));
|
|
tags.push(formatTag);
|
|
}
|
|
break;
|
|
case "audio": {
|
|
if (hit["_source"].hasOwnProperty("format_long_name")) {
|
|
let formatTag = document.createElement("span");
|
|
formatTag.setAttribute("class", "badge badge-pill badge-audio");
|
|
formatTag.appendChild(document.createTextNode(hit["_source"]["format_long_name"]));
|
|
tags.push(formatTag);
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
case "text": {
|
|
let formatTag = document.createElement("span");
|
|
formatTag.setAttribute("class", "badge badge-pill badge-text");
|
|
formatTag.appendChild(document.createTextNode(hit["_source"]["encoding"]));
|
|
tags.push(formatTag);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
//Content
|
|
if (hit.hasOwnProperty("highlight") && hit["highlight"].hasOwnProperty("content")) {
|
|
|
|
let contentDiv = document.createElement("div");
|
|
contentDiv.setAttribute("class", "content-div bg-light");
|
|
contentDiv.insertAdjacentHTML('afterbegin', hit["highlight"]["content"][0]);
|
|
docCard.appendChild(contentDiv);
|
|
}
|
|
|
|
//Audio
|
|
if (mimeCategory === "audio" && hit["_source"].hasOwnProperty("format_long_name")) {
|
|
|
|
let audio = document.createElement("audio");
|
|
audio.setAttribute("preload", "none");
|
|
audio.setAttribute("class", "audio-fit fit");
|
|
audio.setAttribute("controls", "");
|
|
audio.setAttribute("type", hit["_source"]["mime"]);
|
|
audio.setAttribute("src", "file/" + hit["_id"]);
|
|
|
|
docCard.appendChild(audio)
|
|
}
|
|
|
|
if (thumbnail !== null) {
|
|
imgWrapper.appendChild(thumbnail);
|
|
docCard.appendChild(imgWrapper);
|
|
}
|
|
if (thumbnailOverlay !== null) {
|
|
imgWrapper.appendChild(thumbnailOverlay);
|
|
}
|
|
|
|
for (let i = 0; i < tags.length; i++) {
|
|
tagContainer.appendChild(tags[i]);
|
|
}
|
|
|
|
|
|
}
|
|
|
|
//Size tag
|
|
let sizeTag = document.createElement("small");
|
|
sizeTag.appendChild(document.createTextNode(humanFileSize(hit["_source"]["size"])));
|
|
sizeTag.setAttribute("class", "text-muted");
|
|
tagContainer.appendChild(sizeTag);
|
|
|
|
|
|
//Download button
|
|
downloadPopover(docCard, hit["_id"]);
|
|
|
|
docCardBody.appendChild(link);
|
|
docCard.appendChild(docCardBody);
|
|
|
|
link.appendChild(title);
|
|
docCardBody.appendChild(tagContainer);
|
|
|
|
return docCard;
|
|
}
|
|
|
|
function makePageIndicator(searchResult) {
|
|
let pageIndicator = document.createElement("div");
|
|
pageIndicator.appendChild(document.createTextNode(docCount + " / " +searchResult["hits"]["total"]));
|
|
return pageIndicator;
|
|
}
|
|
|
|
|
|
function insertHits(resultContainer, hits) {
|
|
for (let i = 0 ; i < hits.length; i++) {
|
|
resultContainer.appendChild(createDocCard(hits[i]));
|
|
docCount++;
|
|
}
|
|
}
|
|
|
|
window.addEventListener("scroll", function () {
|
|
|
|
if (!coolingDown) {
|
|
|
|
let threshold = 350;
|
|
|
|
if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight - threshold) {
|
|
//load next page
|
|
|
|
let xhttp = new XMLHttpRequest();
|
|
xhttp.onreadystatechange = function() {
|
|
if (this.readyState === 4 && this.status === 200) {
|
|
|
|
let searchResult = JSON.parse(this.responseText);
|
|
let searchResults = document.getElementById("searchResults");
|
|
let hits = searchResult["hits"]["hits"];
|
|
|
|
//Page indicator
|
|
let pageIndicator = makePageIndicator(searchResult);
|
|
searchResults.appendChild(pageIndicator);
|
|
|
|
//Result container
|
|
let resultContainer = makeResultContainer();
|
|
searchResults.appendChild(resultContainer);
|
|
|
|
insertHits(resultContainer, hits);
|
|
|
|
initPopover();
|
|
|
|
if (hits.length !== 0) {
|
|
coolingDown = false;
|
|
}
|
|
}
|
|
};
|
|
xhttp.open("GET", "/scroll?scroll_id=" + scroll_id, true);
|
|
xhttp.send();
|
|
coolingDown = true;
|
|
}
|
|
}
|
|
});
|
|
|
|
function getSelectedMimeTypes() {
|
|
let mimeTypes = [];
|
|
|
|
let selected = tree.selected();
|
|
|
|
for (let i = 0; i < selected.length; i++) {
|
|
|
|
if(selected[i].id === "any") {
|
|
return "any"
|
|
}
|
|
|
|
//Only get children
|
|
if (selected[i].text.indexOf("(") !== -1) {
|
|
mimeTypes.push(selected[i].id);
|
|
}
|
|
}
|
|
|
|
return mimeTypes
|
|
}
|
|
|
|
function search() {
|
|
|
|
if (searchQueued === true) {
|
|
searchQueued = false;
|
|
|
|
//Clear old search results
|
|
let searchResults = document.getElementById("searchResults");
|
|
while (searchResults.firstChild) {
|
|
searchResults.removeChild(searchResults.firstChild);
|
|
}
|
|
|
|
let query = searchBar.value;
|
|
|
|
let xhttp = new XMLHttpRequest();
|
|
xhttp.onreadystatechange = function() {
|
|
if (this.readyState === 4 && this.status === 200) {
|
|
|
|
let searchResult = JSON.parse(this.responseText);
|
|
scroll_id = searchResult["_scroll_id"];
|
|
|
|
//Search stats
|
|
searchResults.appendChild(makeStatsCard(searchResult));
|
|
|
|
//Autocomplete
|
|
if (searchResult.hasOwnProperty("suggest") && searchResult["suggest"].hasOwnProperty("path")) {
|
|
pathAutoComplete = [];
|
|
for (let i = 0; i < searchResult["suggest"]["path"][0]["options"].length; i++) {
|
|
pathAutoComplete.push(searchResult["suggest"]["path"][0]["options"][i].text)
|
|
}
|
|
}
|
|
|
|
|
|
//Setup page
|
|
let resultContainer = makeResultContainer();
|
|
searchResults.appendChild(resultContainer);
|
|
|
|
//Insert search results (hits)
|
|
docCount = 0;
|
|
insertHits(resultContainer, searchResult["hits"]["hits"]);
|
|
|
|
//Initialise download/view button popover
|
|
initPopover();
|
|
}
|
|
};
|
|
|
|
xhttp.open("POST", "/search", true);
|
|
|
|
let postBody = {};
|
|
postBody.q = query;
|
|
postBody.size_min = size_min;
|
|
postBody.size_max = size_max;
|
|
postBody.mime_types = getSelectedMimeTypes();
|
|
postBody.must_match = document.getElementById("barToggle").checked;
|
|
postBody.directories = selectedDirs;
|
|
postBody.path = pathBar.value.replace(/\/$/, "").toLowerCase(); //remove trailing slashes
|
|
xhttp.setRequestHeader('content-type', 'application/json');
|
|
xhttp.send(JSON.stringify(postBody));
|
|
}
|
|
}
|
|
|
|
let pathAutoComplete = [];
|
|
let size_min = 0;
|
|
let size_max = 10000000000000;
|
|
|
|
searchBar.addEventListener("keyup", function () {
|
|
searchQueued = true;
|
|
});
|
|
|
|
//Size slider
|
|
$("#sizeSlider").ionRangeSlider({
|
|
type: "double",
|
|
grid: false,
|
|
force_edges: true,
|
|
min: 0,
|
|
max: 3684.03149864,
|
|
from: 0,
|
|
to: 3684.03149864,
|
|
min_interval: 5,
|
|
drag_interval: true,
|
|
prettify: function (num) {
|
|
|
|
if(num === 0) {
|
|
return "0 B"
|
|
} else if (num >= 3684) {
|
|
return humanFileSize(num * num * num) + "+";
|
|
}
|
|
|
|
return humanFileSize(num * num * num)
|
|
},
|
|
onChange: function(e) {
|
|
size_min = (e.from * e.from * e.from);
|
|
size_max = (e.to * e.to * e.to);
|
|
|
|
if (e.to >= 3684) {
|
|
size_max = 10000000000000;
|
|
}
|
|
|
|
searchQueued = true;
|
|
}
|
|
});
|
|
|
|
//Directories select
|
|
function updateDirectories() {
|
|
let selected = $('#directories').find('option:selected');
|
|
selectedDirs = [];
|
|
$(selected).each(function(){
|
|
selectedDirs.push(parseInt($(this).val()));
|
|
});
|
|
|
|
searchQueued = true;
|
|
}
|
|
document.getElementById("directories").addEventListener("change", updateDirectories);
|
|
updateDirectories();
|
|
searchQueued = false;
|
|
|
|
//Suggest
|
|
function getPathChoices() {
|
|
return new Promise(getPaths => {
|
|
|
|
let xhttp = new XMLHttpRequest();
|
|
xhttp.onreadystatechange = function() {
|
|
if (this.readyState === 4 && this.status === 200) {
|
|
getPaths(JSON.parse(xhttp.responseText))
|
|
}
|
|
};
|
|
xhttp.open("GET", "/suggest?prefix=" + pathBar.value, true);
|
|
xhttp.send();
|
|
});
|
|
}
|
|
|
|
document.getElementById("pathBar").addEventListener("keyup", function () {
|
|
searchQueued = true;
|
|
});
|
|
|
|
window.setInterval(search, 300); |