Skip to content
Permalink
Browse files
Finish work on search bar on the site
  • Loading branch information
LadyCailin committed Apr 3, 2020
1 parent a02a5bd commit c06d22fe79082d37cf3b5fb8fa875711f934fa32
Show file tree
Hide file tree
Showing 10 changed files with 170 additions and 88 deletions.
@@ -11,13 +11,42 @@
*/
public class MasterSearchIndex {

private final Map<String, List<String>> segments = new HashMap<>();
private static class IndexEntry {
private final List<String> segments;
private final String title;
private final ResultType type;

void addSegment(String toLocation, String segment) {
public IndexEntry(String title, ResultType type) {
this.segments = new ArrayList<>();
this.title = title;
this.type = type;
}

public void addSegment(String segment) {
this.segments.add(segment);
}

public List<String> getSegments() {
return this.segments;
}

public String getTitle() {
return this.title;
}

public ResultType getType() {
return type;
}

}

private final Map<String, IndexEntry> segments = new HashMap<>();

void addSegment(String title, String toLocation, ResultType type, String segment) {
if(!segments.containsKey(toLocation)) {
segments.put(toLocation, new ArrayList<>());
segments.put(toLocation, new IndexEntry(title, type));
}
segments.get(toLocation).add(segment);
segments.get(toLocation).addSegment(segment);
}

/**
@@ -37,14 +66,19 @@ void addSegment(String toLocation, String segment) {
* @return
*/
public String getIndex() {
Map<String, List<String>> index = new HashMap<>();
for(Map.Entry<String, List<String>> entry : segments.entrySet()) {
Map<String, List<Object>> index = new HashMap<>();
for(Map.Entry<String, IndexEntry> entry : segments.entrySet()) {
String location = entry.getKey();
for(String string : entry.getValue()) {
String title = entry.getValue().getTitle();
for(String string : entry.getValue().getSegments()) {
if(!index.containsKey(string)) {
index.put(string, new ArrayList<>());
}
index.get(string).add(location);
Map<String, String> locationData = new HashMap<>();
locationData.put("location", location);
locationData.put("title", title);
locationData.put("type", entry.getValue().getType().name());
index.get(string).add(locationData);
}
}
return JSONObject.toJSONString(index);
@@ -0,0 +1,17 @@
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
package com.laytonsmith.tools.docgen.localization;

/**
*
*/
public enum ResultType {
FUNCTION,
EVENT,
OBJECT,
ARTICLE,
API
}
@@ -182,13 +182,19 @@ public boolean hasMasterTranslation(Locale locale, String key) {
* a search index based on the input segments. For English, this index can be used as is, but for other languages,
* this index must also be localized. The index segments will all be in the translation database, however, so
* this process can be automatic. In any case, this function does not handle that.
* @param toLocation
* @param inputString
* @param title The page title, used for the search feature
* @param toLocation The location of the page
* @param type The result type
* @param inputString The page content
*/
public void createTranslationMemory(String toLocation, String inputString) {
Set<String> segments = TranslationMaster.findSegments(inputString);
public void createTranslationMemory(String title, String toLocation,
ResultType type, String inputString) {
for(String searchSegment : TranslationMaster.findSegments(inputString, true)) {
masterSearchIndex.addSegment(title, toLocation, type, searchSegment);
}
Set<String> segments = TranslationMaster.findSegments(inputString, false);

for(String segment : segments) {
masterSearchIndex.addSegment(toLocation, segment);
int id;
if(!translationSummary.containsTranslation(segment)) {
id = getNewId();
@@ -471,9 +477,10 @@ public MasterSearchIndex getSearchIndex() {
* the chance of collisions, as well as reducing the chance of retranslation needed when just parts of a page
* change. This is a best effort attempt, and isn't perfect.
* @param inputString
* @param forSearch For search segment purposes, we want to not filter out some segments.
* @return
*/
public static Set<String> findSegments(String inputString) {
public static Set<String> findSegments(String inputString, boolean forSearch) {
Set<String> segments = new HashSet<>();
// First, remove all things that shouldn't be translated, code blocks, html, etc
inputString = inputString.replaceAll("\r", "");
@@ -523,16 +530,18 @@ public static Set<String> findSegments(String inputString) {
inputString = inputString.replaceAll(URL_PATTERN, "%s");
inputString = inputString.replaceAll("(?s)<.*?>", "%s");

for(String uniqueSegment : UNIQUE_SEGMENTS) {
if(inputString.contains(uniqueSegment)) {
// We have to add it here so it ends up in the page file
segments.add(uniqueSegment);
inputString = inputString.replace(uniqueSegment, "");
if(!forSearch) {
for(String uniqueSegment : UNIQUE_SEGMENTS) {
if(inputString.contains(uniqueSegment)) {
// We have to add it here so it ends up in the page file
segments.add(uniqueSegment);
inputString = inputString.replace(uniqueSegment, "");
}
}
}

for(String functionNames : FUNCTION_IDENTIFIERS) {
inputString = inputString.replaceAll(functionNames, "%s");
for(String functionNames : FUNCTION_IDENTIFIERS) {
inputString = inputString.replaceAll(functionNames, "%s");
}
}

// Process tables
@@ -557,9 +566,11 @@ public static Set<String> findSegments(String inputString) {
.map(string -> {
string = string.trim();
string = string.replace("\n", " ");
for(String className : CLASS_NAMES) {
// These are fully qualified, so they are certainly not meant to be translated.
string = string.replace(className, "%s");
if(!forSearch) {
for(String className : CLASS_NAMES) {
// These are fully qualified, so they are certainly not meant to be translated.
string = string.replace(className, "%s");
}
}
// Removing beginning and ending %s in the string has no impact on whether or not a string
// matches, but does increase the performance of the regex, and simplifies the segment for
@@ -582,7 +593,7 @@ public static Set<String> findSegments(String inputString) {
// Strings that are just symbols (or %s) in their entirety can be removed.
.filter((string) -> !string.matches("^(?:[^a-zA-Z]|%s)+$"))
// Segments that are entirely just a function name are removed.
.filter((string) -> !FUNCTION_NAMES.contains(string))
.filter((string) -> !forSearch ? (!FUNCTION_NAMES.contains(string)) : (true))
.filter((string) -> !USELESS_SEGMENTS.contains(string))
.collect(Collectors.toSet());
}
@@ -42,6 +42,7 @@
import com.laytonsmith.tools.docgen.DocGenTemplates.Generator;
import com.laytonsmith.tools.docgen.DocGenTemplates.Generator.GenerateException;
import com.laytonsmith.tools.docgen.localization.MasterSearchIndex;
import com.laytonsmith.tools.docgen.localization.ResultType;
import com.laytonsmith.tools.docgen.templates.Template;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
@@ -908,7 +909,7 @@ private void writePageFromResource(String title, String resource, String toLocat
+ String.format(githubBaseUrl, "resources" + resource)
+ EDIT_THIS_PAGE_POSTAMBLE
+ "</p>";
writePage(title.replace("_", " "), s, toLocation, keywords, description);
writePage(title.replace("_", " "), s, ResultType.ARTICLE, toLocation, keywords, description);
}

/**
@@ -930,23 +931,26 @@ private void writePageFromResource(String title, String resource, String toLocat
*
* @param title The title of the page
* @param body The content body
* @param type The page type
* @param toLocation the location on the remote server
*/
private void writePage(String title, String body, String toLocation) {
writePage(title, body, toLocation, null, "");
private void writePage(String title, String body, ResultType type, String toLocation) {
writePage(title, body, type, toLocation, null, "");
}

/**
* Most pages should use this method instead of the other methods. This takes care of all the steps, including
* substituting the body into the frame, and handling all the other connections.
*
* @param body The content body
* @param type The type of page this is
* @param title The title of the page
* @param toLocation the location on the remote server
* @param keywords A list of keywords to be added to the meta tag on the page
* @param description A description of the page's content
*/
private void writePage(final String title, final String body, final String toLocation,
private void writePage(final String title, final String body, final ResultType type,
final String toLocation,
List<String> keywords, final String description) {
if(keywords == null) {
keywords = new ArrayList<>();
@@ -968,7 +972,7 @@ private void writePage(final String title, final String body, final String toLoc
if(translationMemoryDb != null) {
generateQueue.submit(() -> {
try {
createTranslationMemory(toLocation, body);
createTranslationMemory(title, toLocation, type, body);
} catch (Throwable t) {
writeLog("While generating translation memory for " + toLocation + "an error occured: ",
t);
@@ -1039,13 +1043,15 @@ private void writePage(final String title, final String body, final String toLoc
* necessary, so the translation memories (tmem) files are created and committed to a repository, so PRs can
* be created. This function is charged with orchestrating the process, which is comprised of several smaller tasks.
* @param toLocation
* @param resultType
* @param inputString
*/
private void createTranslationMemory(String toLocation, String inputString) throws IOException {
private void createTranslationMemory(String title, String toLocation, ResultType type,
String inputString) throws IOException {
toLocation = StringUtils.replaceLast(toLocation, "\\.html", ".tmem.xml");
String location = "%s/docs/" + MSVersion.V3_3_4 + "/" + toLocation;
writeStatus("Creating memory file for " + location);
masterMemories.createTranslationMemory(location, inputString);
masterMemories.createTranslationMemory(title, location, type, inputString);
}

private void writeMasterTranslations() throws IOException {
@@ -1073,8 +1079,7 @@ private void writeSearchIndex() throws IOException {
writeStatus("Generating and uploading search index");
MasterSearchIndex index = masterMemories.getSearchIndex();
writeFromString(index.getIndex(), "searchIndex.json");
// For now, just hardcode false, until it's ready to be switched on.
writeFromString("{\"searchIndexExists\":false}", "searchIndexExists.json");
writeFromString("{\"searchIndexExists\":true}", "searchIndexExists.json");
} else {
writeFromString("{\"searchIndexExists\":false}", "searchIndexExists.json");
}
@@ -1353,7 +1358,7 @@ private void deployAPI() {
+ "});\n"
+ "});\n"
+ "</script>");
writePage("API", b.toString(), "API.html",
writePage("API", b.toString(), ResultType.API, "API.html",
Arrays.asList(new String[]{"API", "functions"}),
"A list of all " + Implementation.GetServerType().getBranding() + " functions");
currentGenerateTask.addAndGet(1);
@@ -1510,7 +1515,8 @@ private void generateFunctionDocs(Function f, DocGen.DocInfo docs) {
+ " (Note this page is automatically generated from the documentation in the source code.)</p>";
page.append(bW);
String description = f.getName() + "() api page";
writePage(f.getName(), page.toString(), "API/functions/" + f.getName() + ".html", Arrays.asList(
writePage(f.getName(), page.toString(), ResultType.FUNCTION, "API/functions/" + f.getName() + ".html",
Arrays.asList(
new String[]{f.getName(), f.getName() + " api", f.getName() + " example", f.getName()
+ " description"}), description);
}
@@ -1615,7 +1621,7 @@ private void deployEventAPI() {
writeLog("While processing " + clazz + " got:", ex);
}
}
writePage("Event API", b.toString(), "Event_API.html",
writePage("Event API", b.toString(), ResultType.API, "Event_API.html",
Arrays.asList(new String[]{"API", "events"}),
"A list of all " + Implementation.GetServerType().getBranding() + " events");
currentGenerateTask.addAndGet(1);
@@ -1,3 +1,5 @@
{{unimplemented}}

MethodScript supports templating for web (or any other template needs) through template
language tags. In many ways, the support for templates is much like JSP and PHP, but
differs in a few key ways, which allow greater flexibility when creating text via
@@ -80,7 +80,7 @@
<body>
<!-- Header -->
<header id="header">
<img src="%%cacheBuster|images/CommandHelper_Icon.png%%" alt=""/>
<img src="%%cacheBuster|images/CommandHelper_Icon.png%%" alt="" class="header-icon"/>
<h1><a id="mainBranding" href="%%siteRoot%%">%%branding%%</a></h1>
<nav id="nav">
<ul>
@@ -1,6 +1,6 @@
/* global Cookies, showLearningTrail, skel, pageRender, wiky, bodyEscaped, apiJsonVersion */
/* global Cookies, showLearningTrail, skel, pageRender, wiky, bodyEscaped, apiJsonVersion, search */

(function ($, skel, wiky, bodyEscaped, showLearningTrail, pageRender) {
(function ($, skel, wiky, bodyEscaped, showLearningTrail, pageRender, search) {
var resourceBase = "%%resourceBase%%";
var docsBase = "%%docsBase%%";
var productionTranslations = "%%productionTranslations%%";
@@ -230,7 +230,7 @@
}

function renderSmall() {
$learningTrail.html(generateLearningTrail(learningTrailJSON, false));
$learningTrail.html(generateLearningTrail(learningTrailJSON, false));
}

function renderXSmall() {
@@ -439,7 +439,7 @@

$(function () {
var url = new URL(window.location.href);
if(url.hostname === "localhost") {
if(url.hostname === "localhost" || url.hostname === "127.0.0.1") {
$("#header").css("background-color", "red");
$("#mainBranding").text("------LOCALHOST DOCS------");
}
@@ -475,5 +475,5 @@
skel.on("+medium", renderSmall);
skel.on("-xsmall", renderNoXSmall);
skel.on("+xsmall", renderXSmall);
search.load(docsBase);
})(jQuery, skel, wiky, bodyEscaped, showLearningTrail, pageRender);
search.load(docsBase, skel);
})(jQuery, skel, wiky, bodyEscaped, showLearningTrail, pageRender, search);
@@ -190,27 +190,7 @@ code {
font-family: inherit;
font-size: 20px;
color: #2c3e50;
}

input[type="text"].sb-search-input {
-webkit-appearance: none;
-webkit-border-radius: 0px;
}

.sb-search-input::-webkit-input-placeholder {
color: #efb480;
}

.sb-search-input:-moz-placeholder {
color: #efb480;
}

.sb-search-input::-moz-placeholder {
color: #efb480;
}

.sb-search-input:-ms-input-placeholder {
color: #efb480;
}

.sb-icon-search,
@@ -274,12 +254,21 @@ input[type="text"].sb-search-input {
.sb-search-results {
left: -220px;
top: 40px;
min-width: 280px;
min-width: 500px;
position: absolute;
background-color: #202222;
color: black;
border: green 2px solid;
display: none; /* Initially hidden, until the user types something*/
overflow: auto;
max-width: 750px;
max-height: 80vh;
}

.sb-search-result-type {
font-variant: small-caps;
font-size: x-small;
color: gray;
}

.sb-search-results a {
@@ -317,6 +306,7 @@ input[type="text"].sb-search-input {
text-align: center;
margin: 0;
display: none;
color: white;
}

.sb-icon-search-close {

0 comments on commit c06d22f

Please sign in to comment.