diff --git a/hmml_to_html/hmml_to_html.c b/hmml_to_html/hmml_to_html.c
index d250590..4010734 100644
--- a/hmml_to_html/hmml_to_html.c
+++ b/hmml_to_html/hmml_to_html.c
@@ -5,6 +5,10 @@ ctime -end ${0%.*}.ctm
exit
#endif
+#define DEBUG 1
+
+// TODO(matt): Fully investigate the ClaimedMemory situation
+
typedef unsigned int bool;
#define TRUE 1
@@ -19,9 +23,18 @@ typedef struct
{
char *Location;
char *Ptr;
+ char *ID;
int Size;
} buffer;
+// TODO(matt): Consider putting the ref_info and quote_info into linked lists on the heap, just to avoid all the hardcoded sizes
+
+typedef struct
+{
+ char Date[32];
+ char Text[512];
+} quote_info;
+
typedef struct
{
char Timecode[8];
@@ -42,19 +55,36 @@ typedef struct
typedef struct
{
- char Date[32];
- char Text[512];
-} quote_info;
+ char Category[32];
+ bool IsMedium;
+} category_info;
#define ArrayCount(A) sizeof(A)/sizeof(*(A))
void
-ClaimBuffer(char *MemoryArena, int *ClaimedMemory, buffer *Buffer, int Size)
+ClaimBuffer(char *MemoryArena, int *ClaimedMemory, buffer *Buffer, char *ID, int Size)
{
Buffer->Location = MemoryArena + *ClaimedMemory;
Buffer->Size = Size;
+ Buffer->ID = ID;
*ClaimedMemory += Buffer->Size;
+ *Buffer->Location = '\0';
Buffer->Ptr = Buffer->Location;
+#if DEBUG
+ printf(" Claimed: %s: %d\n"
+ " Total ClaimedMemory: %d\n\n", Buffer->ID, Buffer->Size, *ClaimedMemory);
+#endif
+}
+
+void
+DeclaimBuffer(buffer *Buffer, int *ClaimedMemory)
+{
+ *Buffer->Location = '\0';
+ *ClaimedMemory -= Buffer->Size;
+#if DEBUG
+ printf("Declaimed: %s\n"
+ " Total ClaimedMemory: %d\n\n", Buffer->ID, *ClaimedMemory);
+#endif
}
int
@@ -95,6 +125,15 @@ CopyBuffer(buffer *Dest, buffer *Src)
Src->Ptr = Src->Location;
while(*Src->Ptr)
{
+ // TODO(matt)
+ {
+ if(Dest->Ptr - Dest->Location >= Dest->Size)
+ {
+ printf("Too big! Too big!\n");
+ __asm__("int3");
+
+ }
+ }
*Dest->Ptr++ = *Src->Ptr++;
}
}
@@ -113,10 +152,28 @@ __attribute__ ((format (printf, 2, 3)))
void
CopyStringToBuffer(buffer *Dest, char *Format, ...)
{
+ // TODO(matt):
+ {
+ if(Dest->Ptr - Dest->Location >= Dest->Size)
+ {
+ printf("Too big! Too big!\n");
+ __asm__("int3");
+
+ }
+ }
va_list Args;
va_start(Args, Format);
int Length = vsprintf(Dest->Ptr, Format, Args);
va_end(Args);
+ // TODO(matt):
+ {
+ if(Length + (Dest->Ptr - Dest->Location) >= Dest->Size)
+ {
+ printf("Too big! Too big!\n");
+ __asm__("int3");
+
+ }
+ }
Dest->Ptr += Length;
}
@@ -235,15 +292,6 @@ SanitisePunctuation(char *String)
return String;
}
-char *CategoryMedium[] =
-{
- "blackboard",
- "owl",
- "rant",
- "research",
- "run",
-};
-
int
BuildReference(ref_info *ReferencesArray, int RefIdentifier, int UniqueRefs, HMML_Reference Ref, HMML_Annotation Anno)
{
@@ -280,6 +328,7 @@ BuildReference(ref_info *ReferencesArray, int RefIdentifier, int UniqueRefs, HMM
CopyString(ReferencesArray[UniqueRefs].ID, Ref.isbn);
CopyString(ReferencesArray[UniqueRefs].Source, Ref.author);
CopyString(ReferencesArray[UniqueRefs].RefTitle, Ref.title);
+ //TODO(matt): Look into finding the best ISBN searcher the web has to offer
CopyString(ReferencesArray[UniqueRefs].URL, "http://www.isbnsearch.org/isbn/%s", Ref.isbn);
}
else if(Ref.url && Ref.article && Ref.author)
@@ -318,12 +367,48 @@ BuildReference(ref_info *ReferencesArray, int RefIdentifier, int UniqueRefs, HMM
return 0;
}
+char *CategoryMedium[][3] =
+{
+ // category icon written name
+ { "authored", "🗪", "Chat Comment"}, // TODO(matt): Conditionally handle Chat vs Guest Comments
+ { "blackboard", "🖌", "Blackboard"},
+ { "owl", "🦉", "Owl of Shame"},
+ { "default", "🖮", "Programming"}, // TODO(matt): Potentially make this configurable per project
+ { "rant", "💢", "Rant"},
+ { "research", "📖", "Research"},
+ { "run", "🏃", "In-Game"} // TODO(matt): Potentially make this configurable per project
+};
+
+void
+BuildFilter(category_info *CategoriesArray, int *UniqueCategories, char *Marker)
+{
+ int i = 0;
+ for(i = 0; i < *UniqueCategories; ++i)
+ {
+ if(!StringsDiffer(Marker, CategoriesArray[i].Category))
+ {
+ return;
+ }
+ }
+
+ ++*UniqueCategories;
+ CopyString(CategoriesArray[i].Category, Marker);
+ for(int j = 0; j < ArrayCount(CategoryMedium); ++j)
+ {
+ if(!StringsDiffer(CategoryMedium[j][0], Marker))
+ {
+ CategoriesArray[i].IsMedium = TRUE;
+ }
+ }
+ // TODO(matt): Sort the CategoriesArray
+}
+
void
BuildCategories(buffer *AnnotationClass, buffer *Category, int *MarkerIndex, bool *HasCategory, char *Marker)
{
for(int i = 0; i < ArrayCount(CategoryMedium); ++i)
{
- if(!StringsDiffer(CategoryMedium[i], Marker))
+ if(!StringsDiffer(CategoryMedium[i][0], Marker))
{
CopyStringToBuffer(AnnotationClass, " %s", SanitisePunctuation(Marker));
++*MarkerIndex;
@@ -360,6 +445,11 @@ StringToInt(char *String)
int
BuildQuote(quote_info *Info, char *Speaker, int ID)
{
+ // TODO(matt): Pull these paths from the config
+ // Also notable that there are different paths for different projects
+ //
+ // TODO(matt): Handle csv's double quote escaping stuff
+
char *QuoteDir = "/home/matt/git/GitHub/insofaras/25fc16d58a297a486334";
if(!StringsDiffer(Speaker, "handmade_hero"))
{
@@ -385,12 +475,14 @@ BuildQuote(quote_info *Info, char *Speaker, int ID)
}
fread(Buffer, Length, 1, File);
fclose(File);
+
+ // TODO(matt): Search the quote store in reverse
char *InPtr = Buffer;
while(InPtr - Buffer < Length)
{
- char InID[4] = {0};
+ char InID[4] = { 0 };
char *OutPtr = InID;
while(*InPtr != ',')
{
@@ -442,7 +534,7 @@ GenerateTopicColours(buffer *Colour, char *Topic)
{
for(int i = 0; i < ArrayCount(CategoryMedium); ++i)
{
- if(!StringsDiffer(Topic, CategoryMedium[i]))
+ if(!StringsDiffer(Topic, CategoryMedium[i][0]))
{
return;
}
@@ -450,6 +542,7 @@ GenerateTopicColours(buffer *Colour, char *Topic)
FILE *TopicsFile;
char *TopicsBuffer;
+ // TODO(matt): Consider (optionally) pulling this path from the config
if((TopicsFile = fopen("topics.css", "a+")))
{
fseek(TopicsFile, 0, SEEK_END);
@@ -772,7 +865,7 @@ main(int ArgC, char **Args)
// NOTE(matt): Init MemoryArena
char *MemoryArena;
- int ArenaSize = 1024 * 1024;
+ int ArenaSize = 1024 * 1024 * 4;
if(!(MemoryArena = calloc(ArenaSize, 1)))
{
perror(Args[0]);
@@ -790,6 +883,9 @@ main(int ArgC, char **Args)
buffer Title;
buffer QuoteMenu;
buffer ReferenceMenu;
+ buffer FilterMenu;
+ buffer FilterTopics;
+ buffer FilterMedia;
buffer Player;
buffer Annotation;
@@ -800,6 +896,8 @@ main(int ArgC, char **Args)
buffer Category;
buffer Colour;
+ buffer FilterState;
+
buffer Master;
for(int FileIndex = 1; FileIndex < ArgC; ++FileIndex)
@@ -816,7 +914,7 @@ main(int ArgC, char **Args)
}
#if CONFIG
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Config, 1024);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Config, "Config", 1024);
#endif
HMML_Output HMML = hmml_parse_file(InFile);
@@ -824,16 +922,28 @@ main(int ArgC, char **Args)
if(HMML.well_formed)
{
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Title, 1024 * 16);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Master, "Master", 1024 * 512);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Player, "Player", 1024 * 256);
+
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Title, "Title", 1024 * 16);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &FilterMenu, "FilterMenu", 1024 * 16);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &FilterTopics, "FilterTopics", 1024 * 8);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &FilterMedia, "FilterMedia", 1024 * 8);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &FilterState, "FilterState", 1024 * 4);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &ReferenceMenu, "ReferenceMenu", 1024 * 16);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &QuoteMenu, "QuoteMenu", 1024 * 16);
+
ref_info ReferencesArray[200] = { 0 };
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Player, 1024 * 256);
+ category_info CategoriesArray[64] = { 0 };
bool HasQuoteMenu = FALSE;
bool HasReferenceMenu = FALSE;
+ bool HasFilterMenu = FALSE;
int QuoteIdentifier = 0x3b1;
int RefIdentifier = 1;
int UniqueRefs = 0;
+ int UniqueCategories = 0;
CopyStringToBuffer(&Title,
"
\n"
@@ -846,6 +956,9 @@ main(int ArgC, char **Args)
for(int AnnotationIndex = 0; AnnotationIndex < HMML.annotation_count; ++AnnotationIndex)
{
+#if DEBUG
+ printf("%d\n", AnnotationIndex);
+#endif
HMML_Annotation *Anno = HMML.annotations + AnnotationIndex;
bool HasCategory = FALSE;
bool HasQuote = FALSE;
@@ -853,11 +966,10 @@ main(int ArgC, char **Args)
quote_info QuoteInfo = { 0 };
- ClaimBuffer(MemoryArena, &ClaimedMemory, &AnnotationHeader, 512);
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Category, 256);
- ClaimBuffer(MemoryArena, &ClaimedMemory, &AnnotationClass, 256);
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Text, 1024 * 4);
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Colour, 32);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &AnnotationHeader, "AnnotationHeader", 512);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &AnnotationClass, "AnnotationClass", 256);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Text, "Text", 1024 * 4);
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Colour, "Colour", 32);
CopyStringToBuffer(&AnnotationHeader,
"
time));
if(Anno->author)
{
+ if(!HasFilterMenu)
+ {
+ HasFilterMenu = TRUE;
+ }
+ BuildFilter(CategoriesArray, &UniqueCategories, "authored");
CopyStringToBuffer(&AnnotationClass, " authored");
CopyStringToBuffer(&Text,
"
%s ",
@@ -890,6 +1007,7 @@ Anno->author);
{
CopyStringToBuffer(&Text,
// TODO(matt): Hoverbox
+ // We should get instructions on how to get this info in the config
"
%.*s",
Anno->markers[MarkerIndex].marker,
StringToColourHash(&Colour, Anno->markers[MarkerIndex].marker),
@@ -901,6 +1019,7 @@ StringLength(Readable), InPtr);
{
CopyStringToBuffer(&Text,
// TODO(matt): Hoverbox
+ // We should get instructions on how to get this info in the config
"
%s",
Anno->markers[MarkerIndex].marker,
StringToColourHash(&Colour, Anno->markers[MarkerIndex].marker),
@@ -911,6 +1030,16 @@ Readable);
else if(Anno->markers[MarkerIndex].type == HMML_CATEGORY)
{
GenerateTopicColours(&Colour, Anno->markers[MarkerIndex].marker);
+ // TODO(matt): Maybe stuff this into BuildCategories
+ if(!HasFilterMenu)
+ {
+ HasFilterMenu = TRUE;
+ }
+ BuildFilter(CategoriesArray, &UniqueCategories, Anno->markers[MarkerIndex].marker);
+ if(!HasCategory)
+ {
+ ClaimBuffer(MemoryArena, &ClaimedMemory, &Category, "Category", 256);
+ }
BuildCategories(&AnnotationClass, &Category, &MarkerIndex, &HasCategory, Anno->markers[MarkerIndex].marker);
}
}
@@ -921,8 +1050,6 @@ Readable);
HMML_Reference *CurrentRef = Anno->references + RefIndex;
if(!HasReferenceMenu)
{
- ClaimBuffer(MemoryArena, &ClaimedMemory, &ReferenceMenu, 1024 * 16);
-
CopyStringToBuffer(&ReferenceMenu,
" \n"
"
\n");
CopyBuffer(&Title, &QuoteMenu);
- ClaimedMemory -= QuoteMenu.Size;
}
if(HasReferenceMenu)
@@ -1226,9 +1377,108 @@ ReferencesArray[i].Identifier[j].Timecode);
"
\n"
" \n");
CopyBuffer(&Title, &ReferenceMenu);
- ClaimedMemory -= ReferenceMenu.Size;
}
+ if(HasFilterMenu)
+ {
+ CopyStringToBuffer(&FilterState, "var filterState = {\n");
+ for(int i = 0; i < UniqueCategories; ++i)
+ {
+ CopyStringToBuffer(&FilterState, "\"%s\":\t{ \"type\": \"%s\",\t\"off\": false },\n",
+ CategoriesArray[i].Category, CategoriesArray[i].IsMedium ? "medium" : "topic");
+ }
+ CopyStringToBuffer(&FilterState, "};\n"
+ "\n");
+
+ CopyStringToBuffer(&FilterMenu,
+" \n"
+" \n");
+ }
+
+ CopyBuffer(&Title, &FilterMenu);
+
#if CONFIG
// TODO(matt): Here is where I test ParseConfig
ParseConfig(&Config, HMML.metadata.annotator);
@@ -1243,8 +1493,10 @@ HMML.metadata.annotator);
" \n");
//NOTE(matt): Collate the buffers!
+#if DEBUG
+ printf("Buffer Collation\n\n");
+#endif
- ClaimBuffer(MemoryArena, &ClaimedMemory, &Master, 1024 * 512);
CopyStringToBuffer(&Master,
"\n"
" \n"
@@ -1260,9 +1512,7 @@ HMML.metadata.annotator);
//NOTE(matt): Here is where we do all our CopyBuffer() calls
CopyBuffer(&Master, &Title);
- ClaimedMemory -= Title.Size;
CopyBuffer(&Master, &Player);
- ClaimedMemory -= Player.Size;
//
CopyStringToBuffer(&Master,
@@ -1299,6 +1549,292 @@ HMML.metadata.annotator);
" });\n"
"}\n"
"\n"
+"var filter = document.querySelector(\".filter\");\n"
+"var filterModeElement = filter.querySelector(\".filter_mode\");\n"
+"var filterMode = filterModeElement.classList[1];\n");
+
+ if(HasFilterMenu)
+ {
+ CopyBuffer(&Master, &FilterState);
+ }
+
+ DeclaimBuffer(&QuoteMenu, &ClaimedMemory);
+ DeclaimBuffer(&ReferenceMenu, &ClaimedMemory);
+ DeclaimBuffer(&FilterState, &ClaimedMemory);
+ DeclaimBuffer(&FilterMedia, &ClaimedMemory);
+ DeclaimBuffer(&FilterTopics, &ClaimedMemory);
+ DeclaimBuffer(&FilterMenu, &ClaimedMemory);
+ DeclaimBuffer(&Title, &ClaimedMemory);
+ DeclaimBuffer(&Player, &ClaimedMemory);
+
+ CopyStringToBuffer(&Master,
+"// Filter Mode Toggle\n"
+"var testMarkers = document.querySelectorAll(\".marker\");\n"
+"filterModeElement.addEventListener(\"click\", function(ev) {\n"
+" if(filterMode == \"inclusive\")\n"
+" {\n"
+" filterModeElement.classList.remove(\"inclusive\");\n"
+" filterModeElement.classList.add(\"exclusive\");\n"
+" filterMode = \"exclusive\";\n"
+"\n"
+" for(var i = 0; i < testMarkers.length; ++i)\n"
+" {\n"
+" var testCategories = testMarkers[i].classList;\n"
+" for(var j = 0; j < testCategories.length; ++j)\n"
+" {\n"
+" if((testCategories[j].startsWith(\"off_\")) && !testMarkers[i].classList.contains(\"skip\"))\n"
+" {\n"
+" testMarkers[i].classList.add(\"skip\");\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+" else\n"
+" {\n"
+" filterModeElement.classList.remove(\"exclusive\");\n"
+" filterModeElement.classList.add(\"inclusive\");\n"
+" filterMode = \"inclusive\";\n"
+"\n"
+" for(var i = 0; i < testMarkers.length; ++i)\n"
+" {\n"
+" var testCategories = testMarkers[i].classList;\n"
+" for(var j = 0; j < testCategories.length; ++j)\n"
+" {\n"
+" if((testCategories[j] in filterState || testCategories[j].startsWith(\"cat_\")) && testMarkers[i].classList.contains(\"skip\"))\n"
+" {\n"
+" testMarkers[i].classList.remove(\"skip\");\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+"});\n"
+"\n"
+"// Filter Toggle\n"
+"var filterCategories = filter.querySelectorAll(\".filter_topics .filter_content,.filter_media .filter_content\");\n"
+"for(var i = 0; i < filterCategories.length; ++i)\n"
+"{\n"
+" filterCategories[i].addEventListener(\"click\", function(ev) {\n"
+" var selectedCategory = this.classList[1];\n"
+" filterState[selectedCategory].off = !filterState[selectedCategory].off;\n"
+"\n"
+" if(filterState[selectedCategory].off)\n"
+" {\n"
+" this.classList.add(\"off\");\n"
+" var testMarkers = document.querySelectorAll(\".marker.\" + selectedCategory + \", .marker.cat_\" + selectedCategory);\n"
+" for(var j = 0; j < testMarkers.length; ++j)\n"
+" {\n"
+" if(filterState[selectedCategory].type == \"topic\")\n"
+" {\n"
+" testMarkers[j].classList.remove(\"cat_\" + selectedCategory);\n"
+" testMarkers[j].classList.add(\"off_\" + selectedCategory);\n"
+" var markerCategories = testMarkers[j].querySelectorAll(\".category.\" + selectedCategory);\n"
+" for(var k = 0; k < markerCategories.length; ++k)\n"
+" {\n"
+" if(markerCategories[k].classList.contains(selectedCategory))\n"
+" {\n"
+" markerCategories[k].classList.add(\"off\");\n"
+" }\n"
+" }\n"
+" }\n"
+" else\n"
+" {\n"
+" testMarkers[j].classList.remove(selectedCategory);\n"
+" testMarkers[j].classList.add(\"off_\" + selectedCategory);\n"
+" }\n"
+"\n"
+" Skipping = 1;\n"
+" if(filterMode == \"exclusive\")\n"
+" {\n"
+" testMarkers[j].classList.add(\"skip\");\n"
+" }\n"
+" else\n"
+" {\n"
+" var markerClasses = testMarkers[j].classList;\n"
+" for(var k = 0; k < markerClasses.length; ++k)\n"
+" {\n"
+" if(markerClasses[k] in filterState || markerClasses[k].replace(/^cat_/, \"\") in filterState)\n"
+" {\n"
+" Skipping = 0;\n"
+" }\n"
+" }\n"
+" if(Skipping)\n"
+" {\n"
+" testMarkers[j].classList.add(\"skip\");\n"
+" }\n"
+" }\n"
+"\n"
+" }\n"
+" }\n"
+" else\n"
+" {\n"
+" this.classList.remove(\"off\");\n"
+" var testMarkers = document.querySelectorAll(\".marker.off_\" + selectedCategory);\n"
+" for(var j = 0; j < testMarkers.length; ++j)\n"
+" {\n"
+" if(filterState[selectedCategory].type == \"topic\")\n"
+" {\n"
+" testMarkers[j].classList.remove(\"off_\" + selectedCategory);\n"
+" testMarkers[j].classList.add(\"cat_\" + selectedCategory);\n"
+" var markerCategories = testMarkers[j].querySelectorAll(\".category.\" + selectedCategory);\n"
+" for(var k = 0; k < markerCategories.length; ++k)\n"
+" {\n"
+" if(markerCategories[k].classList.contains(selectedCategory))\n"
+" {\n"
+" markerCategories[k].classList.remove(\"off\");\n"
+" }\n"
+" }\n"
+" }\n"
+" else\n"
+" {\n"
+" testMarkers[j].classList.remove(\"off_\" + selectedCategory);\n"
+" testMarkers[j].classList.add(selectedCategory);\n"
+" }\n"
+"\n"
+" Skipping = 0;\n"
+" if(filterMode == \"inclusive\")\n"
+" {\n"
+" testMarkers[j].classList.remove(\"skip\");\n"
+" }\n"
+" else\n"
+" {\n"
+" var markerClasses = testMarkers[j].classList;\n"
+" for(var k = 0; k < markerClasses.length; ++k)\n"
+" {\n"
+" if(markerClasses[k].startsWith(\"off_\"))\n"
+" {\n"
+" Skipping = 1;\n"
+" }\n"
+" }\n"
+" if(!Skipping)\n"
+" {\n"
+" testMarkers[j].classList.remove(\"skip\");\n"
+" }\n"
+" }\n"
+" }\n"
+" }\n"
+" });\n"
+"}\n"
+"\n"
+"var refSources = document.querySelectorAll(\".refs .ref\");\n"
+"for (var i = 0; i < refSources.length; ++i) {\n"
+" refSources[i].addEventListener(\"click\", function(ev) {\n"
+" if (player) {\n"
+" player.pause();\n"
+" }\n"
+" });\n"
+"}\n"
+"\n"
+"function resetFade()\n"
+"{\n"
+" filter.classList.remove(\"responsible\");\n"
+" filter.querySelector(\".filter_mode\").classList.remove(\"responsible\");\n"
+" var responsibleCategories = filter.querySelectorAll(\".filter_content.responsible\");\n"
+" for(var i = 0; i < responsibleCategories.length; ++i)\n"
+" {\n"
+" responsibleCategories[i].classList.remove(\"responsible\");\n"
+" }\n"
+"}\n"
+"\n"
+"var sourceMenus = document.querySelectorAll(\".menu\");\n"
+"function onRefChanged(ref, element) {\n"
+" if(element.classList.contains(\"skip\"))\n"
+" {\n"
+" if(!filter.classList.contains(\"responsible\"))\n"
+" {\n"
+" filter.classList.add(\"responsible\");\n"
+" }\n"
+"\n"
+" for(var selector = 0; selector < element.classList.length; ++selector)\n"
+" {\n"
+" if(element.classList[selector].startsWith(\"off_\"))\n"
+" {\n"
+" if(!filter.querySelector(\".filter_content.\" + element.classList[selector].replace(/^off_/, \"\")).classList.contains(\"responsible\"))\n"
+" {\n"
+" filter.querySelector(\".filter_content.\" + element.classList[selector].replace(/^off_/, \"\")).classList.add(\"responsible\");\n"
+" }\n"
+" }\n"
+" if((element.classList[selector].startsWith(\"cat_\") || element.classList[selector] in filterState))\n"
+" {\n"
+" if(!filter.querySelector(\".filter_mode\").classList.add(\"responsible\"))\n"
+" {\n"
+" filter.querySelector(\".filter_mode\").classList.add(\"responsible\");\n"
+" }\n"
+" }\n"
+" setTimeout(resetFade, 8000);\n"
+" }\n"
+" player.jumpToNextMarker();\n"
+" return;\n"
+" }\n"
+"\n"
+" for (var MenuIndex = 0; MenuIndex < sourceMenus.length; ++MenuIndex)\n"
+" {\n"
+" var SetMenu = 0;\n"
+" if (ref !== undefined && ref !== null) {\n"
+" var refElements = sourceMenus[MenuIndex].querySelectorAll(\".refs .ref\");\n"
+" var refs = ref.split(\",\");\n"
+"\n"
+" for (var i = 0; i < refElements.length; ++i) {\n"
+" if (refs.includes(refElements[i].getAttribute(\"data-id\"))) {\n"
+" refElements[i].classList.add(\"current\");\n"
+" SetMenu = 1;\n"
+" } else {\n"
+" refElements[i].classList.remove(\"current\");\n"
+" }\n"
+" }\n"
+" if(SetMenu) {\n"
+" sourceMenus[MenuIndex].classList.add(\"current\");\n"
+" } else {\n"
+" sourceMenus[MenuIndex].classList.remove(\"current\");\n"
+" }\n"
+"\n"
+" } else {\n"
+" sourceMenus[MenuIndex].classList.remove(\"current\");\n"
+" var refs = sourceMenus[MenuIndex].querySelectorAll(\".refs .ref\");\n"
+" for (var i = 0; i < refs.length; ++i) {\n"
+" refs[i].classList.remove(\"current\");\n"
+" }\n"
+" }\n"
+" }\n"
+"}\n"
+" \n"
+" \n"
+"\n");
+
+#if 0
+ CopyStringToBuffer(&Master,
+" \n"
"