cinera v0.8.0: Mobile-friendly layout
Major features: Search page: Subdivision grid layout Player page: Device orientation-specific layout Fixes: Strip slashes of the URLs: base_url, etc. Fix SnipeChecksumAndCloseFile() to not null-terminate the checksum string Fix hover background colouration of medium icons of current timestamp Fix DeriveLineageWithoutOriginOfProject() to call InitBookOfPointers() Fix SortAndAbbreviateSpeakers() to use the person's ID if Name is blank More directly display the "unit", if set, in the search results Fix VideoIsPrivate() to find the apparently relocated privacyStatus Make VideoIsPrivate() default to TRUE for non-youtube Output as keywords all topics that do not match "nullTopic" Deleted asset: cinera_search.js New assets: cinera_search_pre.js cinera_search_post.js
This commit is contained in:
parent
6eeb588adf
commit
3945ac883c
595
cinera/cinera.c
595
cinera/cinera.c
|
@ -22,8 +22,8 @@ typedef struct
|
|||
|
||||
version CINERA_APP_VERSION = {
|
||||
.Major = 0,
|
||||
.Minor = 7,
|
||||
.Patch = 18
|
||||
.Minor = 8,
|
||||
.Patch = 0
|
||||
};
|
||||
|
||||
#include <stdarg.h> // NOTE(matt): varargs
|
||||
|
@ -119,6 +119,9 @@ clock_t TIMING_START;
|
|||
|
||||
#define MIN(A, B) A < B ? A : B
|
||||
|
||||
typedef int32_t hash32;
|
||||
typedef hash32 asset_hash;
|
||||
|
||||
void
|
||||
Clear(void *V, uint64_t Size)
|
||||
{
|
||||
|
@ -2442,7 +2445,7 @@ typedef struct
|
|||
char BaseURL[MAX_BASE_URL_LENGTH];
|
||||
char SearchLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH];
|
||||
char PlayerLocation[MAX_RELATIVE_PAGE_LOCATION_LENGTH];
|
||||
char PlayerURLPrefix[MAX_PLAYER_URL_PREFIX_LENGTH]; // TODO(matt): Replace this with the OutputPath, when we add that
|
||||
char PlayerURLPrefix[MAX_PLAYER_URL_PREFIX_LENGTH];
|
||||
} db_header_entries4;
|
||||
|
||||
typedef db_entry3 db_entry4;
|
||||
|
@ -2553,7 +2556,7 @@ typedef struct
|
|||
{
|
||||
char Filename[MAX_ASSET_FILENAME_LENGTH];
|
||||
enum8(asset_type) Type;
|
||||
int32_t Hash;
|
||||
hash32 Hash;
|
||||
uint32_t LandmarkCount;
|
||||
uint64_t Associated:1;
|
||||
uint64_t Variants:63;
|
||||
|
@ -2639,7 +2642,7 @@ typedef struct asset
|
|||
{
|
||||
asset_type Type;
|
||||
char Filename[MAX_ASSET_FILENAME_LENGTH];
|
||||
int32_t Hash;
|
||||
asset_hash Hash;
|
||||
vec2 Dimensions;
|
||||
sprite Sprite;
|
||||
uint64_t Variants:63;
|
||||
|
@ -2659,7 +2662,8 @@ asset BuiltinAssets[] =
|
|||
{ ASSET_IMG, "cinera_icon_filter.png" },
|
||||
{ ASSET_JS, "cinera_pre.js" },
|
||||
{ ASSET_JS, "cinera_post.js" },
|
||||
{ ASSET_JS, "cinera_search.js" },
|
||||
{ ASSET_JS, "cinera_search_pre.js" },
|
||||
{ ASSET_JS, "cinera_search_post.js" },
|
||||
{ ASSET_JS, "cinera_player_pre.js" },
|
||||
{ ASSET_JS, "cinera_player_post.js" },
|
||||
};
|
||||
|
@ -2671,7 +2675,8 @@ typedef enum
|
|||
ASSET_IMG_FILTER,
|
||||
ASSET_JS_CINERA_PRE,
|
||||
ASSET_JS_CINERA_POST,
|
||||
ASSET_JS_SEARCH,
|
||||
ASSET_JS_SEARCH_PRE,
|
||||
ASSET_JS_SEARCH_POST,
|
||||
ASSET_JS_PLAYER_PRE,
|
||||
ASSET_JS_PLAYER_POST,
|
||||
BUILTIN_ASSETS_COUNT,
|
||||
|
@ -3457,6 +3462,22 @@ CopyStringToBufferNoFormat_(int LineNumber, buffer *Dest, string String)
|
|||
*Dest->Ptr = '\0';
|
||||
}
|
||||
|
||||
#define CopyStringToBufferNoTerminate(Dest, Src) CopyStringToBufferNoTerminate_(__LINE__, Dest, Src)
|
||||
void
|
||||
CopyStringToBufferNoTerminate_(int LineNumber, buffer *Dest, string Src)
|
||||
{
|
||||
if((Dest->Ptr - Dest->Location + Src.Length) > Dest->Size)
|
||||
{
|
||||
fprintf(stderr, "CopyStringToBufferNoTerminate(%s) call on line %d cannot accommodate %ld-character string:\n"
|
||||
"%.*s\n", BufferIDStrings[Dest->ID], LineNumber, Src.Length, (int)Src.Length, Src.Base);
|
||||
__asm__("int3");
|
||||
}
|
||||
for(int i = 0; i < Src.Length; ++i)
|
||||
{
|
||||
*Dest->Ptr++ = Src.Base[i];
|
||||
}
|
||||
}
|
||||
|
||||
#define CopyStringToBufferNoFormatL(Dest, Length, String) CopyStringToBufferNoFormatL_(__LINE__, Dest, Length, String)
|
||||
void
|
||||
CopyStringToBufferNoFormatL_(int LineNumber, buffer *Dest, int Length, char *String)
|
||||
|
@ -4569,7 +4590,7 @@ PrintAssetAndLandmarks(db_asset *A, uint16_t *Index)
|
|||
|
||||
// TODO(matt): Almost definitely redo this using Locate*() functions...
|
||||
void
|
||||
SnipeChecksumAndCloseFile(file *HTMLFile, db_asset *Asset, int LandmarksInFile, buffer *Checksum, int64_t *RunningLandmarkIndex)
|
||||
SnipeChecksumAndCloseFile(file *HTMLFile, db_asset *Asset, int LandmarksInFile, asset_hash Checksum, int64_t *RunningLandmarkIndex)
|
||||
{
|
||||
db_landmark *FirstLandmark = LocateFirstLandmark(Asset);
|
||||
for(int j = 0; j < LandmarksInFile; ++j, ++*RunningLandmarkIndex)
|
||||
|
@ -4577,7 +4598,9 @@ SnipeChecksumAndCloseFile(file *HTMLFile, db_asset *Asset, int LandmarksInFile,
|
|||
db_landmark *Landmark = FirstLandmark + *RunningLandmarkIndex;
|
||||
|
||||
HTMLFile->Buffer.Ptr = HTMLFile->Buffer.Location + Landmark->Position;
|
||||
CopyBufferSized(&HTMLFile->Buffer, Checksum, Checksum->Ptr - Checksum->Location);
|
||||
char ChecksumString[16];
|
||||
ClearCopyString(ChecksumString, sizeof(ChecksumString), "%08x", Checksum);
|
||||
CopyStringToBufferNoTerminate(&HTMLFile->Buffer, Wrap0(ChecksumString));
|
||||
}
|
||||
|
||||
HTMLFile->Handle = fopen(HTMLFile->Path, "w");
|
||||
|
@ -4996,7 +5019,7 @@ ReadPlayerPageIntoBuffer(file *File, string BaseDir, string PlayerLocation, stri
|
|||
}
|
||||
|
||||
rc
|
||||
SnipeChecksumIntoHTML(db_asset *Asset, buffer *Checksum)
|
||||
SnipeChecksumIntoHTML(db_asset *Asset, asset_hash Checksum)
|
||||
{
|
||||
db_landmark *FirstLandmark = LocateFirstLandmark(Asset);
|
||||
|
||||
|
@ -5564,32 +5587,38 @@ UpdateAssetInDB(asset *Asset)
|
|||
|
||||
if(StoredAsset->Hash != Asset->Hash)
|
||||
{
|
||||
char OldChecksum[16];
|
||||
ClearCopyString(OldChecksum, sizeof(OldChecksum), "%08x", StoredAsset->Hash);
|
||||
|
||||
char NewChecksum[16];
|
||||
ClearCopyString(NewChecksum, sizeof(NewChecksum), "%08x", Asset->Hash);
|
||||
|
||||
StoredAsset->Hash = Asset->Hash;
|
||||
char *Ptr = (char *)Asset;
|
||||
Ptr += sizeof(*Asset);
|
||||
|
||||
buffer Checksum = {};
|
||||
ClaimBuffer(&Checksum, BID_CHECKSUM, 16);
|
||||
CopyStringToBuffer(&Checksum, "%08x", StoredAsset->Hash);
|
||||
|
||||
file AssetFile = {};
|
||||
AssetFile.Path = ConstructAssetPath(&AssetFile, Wrap0i(StoredAsset->Filename, sizeof(StoredAsset->Filename)), StoredAsset->Type);
|
||||
ResolvePath(&AssetFile.Path);
|
||||
|
||||
string ChecksumL = Wrap0i(Checksum.Location, Checksum.Ptr - Checksum.Location);
|
||||
string Message = MakeString("sssslsss",
|
||||
ColourStrings[CS_ONGOING], "Updating", ColourStrings[CS_END], " checksum ", &ChecksumL, " of ", AssetFile.Path, " in HTML files");
|
||||
fprintf(stderr, "%.*s", (int)Message.Length, Message.Base);
|
||||
uint64_t MessageLength = Message.Length;
|
||||
FreeString(&Message);
|
||||
string MessageEditType = MakeString("sss", ColourStrings[CS_ONGOING], "Updating", ColourStrings[CS_END]);
|
||||
string Message = MakeString("sssssssssss",
|
||||
" checksum ",
|
||||
ColourStrings[CS_BLACK_BOLD], OldChecksum, ColourStrings[CS_END],
|
||||
" → ",
|
||||
ColourStrings[CS_BLUE_BOLD], NewChecksum, ColourStrings[CS_END],
|
||||
" of ", AssetFile.Path, " in HTML files");
|
||||
fprintf(stderr, "%.*s%.*s", (int)MessageEditType.Length, MessageEditType.Base, (int)Message.Length, Message.Base);
|
||||
uint64_t MessageLength = MessageEditType.Length + Message.Length;
|
||||
|
||||
if(SnipeChecksumIntoHTML(StoredAsset, &Checksum) == RC_SUCCESS)
|
||||
if(SnipeChecksumIntoHTML(StoredAsset, Asset->Hash) == RC_SUCCESS)
|
||||
{
|
||||
ClearTerminalRow(MessageLength);
|
||||
fprintf(stderr, "%sUpdated%s checksum %.*s of %s\n", ColourStrings[CS_REINSERTION], ColourStrings[CS_END], (int)ChecksumL.Length, ChecksumL.Base, AssetFile.Path);
|
||||
PrintC(CS_REINSERTION, "Updated");
|
||||
fprintf(stderr, "%.*s\n", (int)Message.Length, Message.Base);
|
||||
}
|
||||
|
||||
DeclaimBuffer(&Checksum);
|
||||
FreeString(&Message);
|
||||
|
||||
DB.Metadata.File.Handle = fopen(DB.Metadata.File.Path, "w");
|
||||
fwrite(DB.Metadata.File.Buffer.Location, DB.Metadata.File.Buffer.Size, 1, DB.Metadata.File.Handle);
|
||||
|
@ -5625,7 +5654,7 @@ UpdateAssetInDB(asset *Asset)
|
|||
fwrite(&StoredAsset, sizeof(StoredAsset), 1, DB.Metadata.File.Handle);
|
||||
AccumulateFileEditSize(&DB.Metadata, sizeof(StoredAsset));
|
||||
|
||||
printf("%sAppended%s %s asset: %s [%08x]\n", ColourStrings[CS_ADDITION], ColourStrings[CS_END], AssetTypeNames[StoredAsset.Type], StoredAsset.Filename, StoredAsset.Hash);
|
||||
fprintf(stderr, "%sAppended%s %s asset: %s [%08x]\n", ColourStrings[CS_ADDITION], ColourStrings[CS_END], AssetTypeNames[StoredAsset.Type], StoredAsset.Filename, StoredAsset.Hash);
|
||||
|
||||
fwrite(DB.Metadata.File.Buffer.Location + BytesIntoFile, DB.Metadata.File.Buffer.Size - BytesIntoFile, 1, DB.Metadata.File.Handle);
|
||||
|
||||
|
@ -5985,8 +6014,6 @@ AbbreviationsClash(memory_book *Speakers)
|
|||
void
|
||||
SortAndAbbreviateSpeakers(speakers *Speakers)
|
||||
{
|
||||
// TODO(matt): Handle Abbreviation in its new form as a char *, rather than a fixed-sized char[], so probably doing
|
||||
// MakeString0() or ExpandString0() or something
|
||||
for(int i = 0; i < Speakers->Speakers.ItemCount; ++i)
|
||||
{
|
||||
speaker *A = GetPlaceInBook(&Speakers->Speakers, i);
|
||||
|
@ -6006,8 +6033,9 @@ SortAndAbbreviateSpeakers(speakers *Speakers)
|
|||
for(int i = 0; i < Speakers->Speakers.ItemCount; ++i)
|
||||
{
|
||||
speaker *This = GetPlaceInBook(&Speakers->Speakers, i);
|
||||
string Name = This->Person->Name.Length > 0 ? This->Person->Name : This->Person->ID;
|
||||
StringToColourHash(&This->Colour, This->Person->ID);
|
||||
This->Abbreviation = InitialString(&Speakers->Abbreviations, This->Person->Name);
|
||||
This->Abbreviation = InitialString(&Speakers->Abbreviations, Name);
|
||||
}
|
||||
|
||||
int Attempt = 0;
|
||||
|
@ -6016,11 +6044,12 @@ SortAndAbbreviateSpeakers(speakers *Speakers)
|
|||
for(int i = 0; i < Speakers->Speakers.ItemCount; ++i)
|
||||
{
|
||||
speaker *This = GetPlaceInBook(&Speakers->Speakers, i);
|
||||
string Name = This->Person->Name.Length > 0 ? This->Person->Name : This->Person->ID;
|
||||
switch(Attempt)
|
||||
{
|
||||
case 0: This->Abbreviation = GetFirstSubstring(This->Person->Name); break;
|
||||
case 1: This->Abbreviation = InitialAndGetFinalString(&Speakers->Abbreviations, This->Person->Name); break;
|
||||
case 2: This->Abbreviation = This->Person->Name; break;
|
||||
case 0: This->Abbreviation = GetFirstSubstring(Name); break;
|
||||
case 1: This->Abbreviation = InitialAndGetFinalString(&Speakers->Abbreviations, Name); break;
|
||||
case 2: This->Abbreviation = Name; break;
|
||||
}
|
||||
}
|
||||
++Attempt;
|
||||
|
@ -6405,6 +6434,8 @@ PushCredentials(buffer *CreditsMenu, memory_book *Speakers, person *Actor, role
|
|||
|
||||
CopyStringToBuffer(CreditsMenu,
|
||||
" <span class=\"credit\">\n");
|
||||
|
||||
string Name = Actor->Name.Length > 0 ? Actor->Name : Actor->ID;
|
||||
if(Actor->Homepage.Length)
|
||||
{
|
||||
CopyStringToBuffer(CreditsMenu,
|
||||
|
@ -6414,7 +6445,7 @@ PushCredentials(buffer *CreditsMenu, memory_book *Speakers, person *Actor, role
|
|||
" </a>\n",
|
||||
(int)Actor->Homepage.Length, Actor->Homepage.Base,
|
||||
RoleStrings[Role],
|
||||
(int)Actor->Name.Length, Actor->Name.Base);
|
||||
(int)Name.Length, Name.Base);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -6424,7 +6455,7 @@ PushCredentials(buffer *CreditsMenu, memory_book *Speakers, person *Actor, role
|
|||
" <div class=\"name\">%.*s</div>\n"
|
||||
" </div>\n",
|
||||
RoleStrings[Role],
|
||||
(int)Actor->Name.Length, Actor->Name.Base);
|
||||
(int)Name.Length, Name.Base);
|
||||
}
|
||||
|
||||
// TODO(matt): Handle multiple support platforms!
|
||||
|
@ -6462,9 +6493,9 @@ ErrorCredentials(string HMMLFilepath, string Actor, role Role)
|
|||
}
|
||||
|
||||
int
|
||||
BuildCredits(string HMMLFilepath, buffer *CreditsMenu, HMML_VideoMetaData *Metadata, speakers *Speakers, bool *RequiresCineraJS)
|
||||
BuildCredits(string HMMLFilepath, buffer *CreditsMenu, HMML_VideoMetaData *Metadata, person *Host, speakers *Speakers, bool *RequiresCineraJS)
|
||||
{
|
||||
person *Host = GetPersonFromConfig(Wrap0(Metadata->member));
|
||||
//person *Host = GetPersonFromConfig(Wrap0(Metadata->member));
|
||||
if(Host)
|
||||
{
|
||||
PushCredentials(CreditsMenu, &Speakers->Speakers, Host, R_HOST, RequiresCineraJS);
|
||||
|
@ -8709,61 +8740,73 @@ ExamineDB(void)
|
|||
DeclaimMenuBuffers(&MenuBuffers)
|
||||
|
||||
bool
|
||||
VideoIsPrivate(char *VideoID)
|
||||
VideoIsPrivate(string VODPlatform, char *VideoID)
|
||||
{
|
||||
// TODO(matt): Redo this to only return once, at the end
|
||||
|
||||
// NOTE(matt): Currently only supports YouTube
|
||||
// NOTE(matt): Stack-string
|
||||
char Message[128];
|
||||
CopyString(Message, sizeof(Message), "%sChecking%s privacy status of: https://youtube.com/watch?v=%s", ColourStrings[CS_ONGOING], ColourStrings[CS_END], VideoID);
|
||||
fprintf(stderr, "%s", Message);
|
||||
int MessageLength = StringLength(Message);
|
||||
buffer VideoAPIResponse;
|
||||
ClaimBuffer(&VideoAPIResponse, BID_VIDEO_API_RESPONSE, Kilobytes(1));
|
||||
if(StringsMatch(Wrap0("youtube"), VODPlatform))
|
||||
{
|
||||
char Message[128];
|
||||
CopyString(Message, sizeof(Message), "%sChecking%s privacy status of: https://youtube.com/watch?v=%s", ColourStrings[CS_ONGOING], ColourStrings[CS_END], VideoID);
|
||||
fprintf(stderr, "%s", Message);
|
||||
int MessageLength = StringLength(Message);
|
||||
buffer VideoAPIResponse;
|
||||
ClaimBuffer(&VideoAPIResponse, BID_VIDEO_API_RESPONSE, Kilobytes(1));
|
||||
|
||||
CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
LastPrivacyCheck = time(0);
|
||||
CURL *curl = curl_easy_init();
|
||||
if(curl) {
|
||||
LastPrivacyCheck = time(0);
|
||||
#define APIKey "AIzaSyAdV2U8ivPk8PHMaPMId0gynksw_gdzr9k"
|
||||
// NOTE(matt): Stack-string
|
||||
char URL[1024] = {0};
|
||||
CopyString(URL, sizeof(URL), "https://www.googleapis.com/youtube/v3/videos?key=%s&part=status&id=%s", APIKey, VideoID);
|
||||
CURLcode CurlReturnCode;
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &VideoAPIResponse.Ptr);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlIntoBuffer);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||
if((CurlReturnCode = curl_easy_perform(curl)))
|
||||
{
|
||||
fprintf(stderr, "%s\n", curl_easy_strerror(CurlReturnCode));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
// NOTE(matt): Stack-string
|
||||
char URL[1024] = {0};
|
||||
CopyString(URL, sizeof(URL), "https://www.googleapis.com/youtube/v3/videos?key=%s&part=status&id=%s", APIKey, VideoID);
|
||||
CURLcode CurlReturnCode;
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &VideoAPIResponse.Ptr);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CurlIntoBuffer);
|
||||
curl_easy_setopt(curl, CURLOPT_URL, URL);
|
||||
// TODO(matt): Handle the case when our API quota has depleted / expired
|
||||
if((CurlReturnCode = curl_easy_perform(curl)))
|
||||
{
|
||||
fprintf(stderr, "%s\n", curl_easy_strerror(CurlReturnCode));
|
||||
}
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
VideoAPIResponse.Ptr = VideoAPIResponse.Location;
|
||||
// TODO(matt): Parse this JSON
|
||||
SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
SeekBufferForString(&VideoAPIResponse, "\"totalResults\": ", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
if(*VideoAPIResponse.Ptr == '0')
|
||||
{
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
// printf("Private video: https://youtube.com/watch?v=%s\n", VideoID);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return TRUE;
|
||||
}
|
||||
SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
SeekBufferForString(&VideoAPIResponse, "\"privacyStatus\": \"", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
// NOTE(matt): Stack-string
|
||||
char Status[16];
|
||||
CopyStringNoFormatT(Status, sizeof(Status), VideoAPIResponse.Ptr, '\"');
|
||||
if(!StringsDiffer0(Status, "public"))
|
||||
{
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return FALSE;
|
||||
VideoAPIResponse.Ptr = VideoAPIResponse.Location;
|
||||
// TODO(matt): Parse this JSON
|
||||
SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
SeekBufferForString(&VideoAPIResponse, "\"totalResults\": ", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
if(*VideoAPIResponse.Ptr == '0')
|
||||
{
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
// printf("Private video: https://youtube.com/watch?v=%s\n", VideoID);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VideoAPIResponse.Ptr = VideoAPIResponse.Location;
|
||||
SeekBufferForString(&VideoAPIResponse, "{", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
SeekBufferForString(&VideoAPIResponse, "\"privacyStatus\": \"", C_SEEK_FORWARDS, C_SEEK_AFTER);
|
||||
// NOTE(matt): Stack-string
|
||||
char Status[16];
|
||||
CopyStringNoFormatT(Status, sizeof(Status), VideoAPIResponse.Ptr, '\"');
|
||||
if(!StringsDiffer0(Status, "public"))
|
||||
{
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
// printf("Unlisted video: https://youtube.com/watch?v=%s\n", VideoID);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
DeclaimBuffer(&VideoAPIResponse);
|
||||
// printf("Unlisted video: https://youtube.com/watch?v=%s\n", VideoID);
|
||||
ClearTerminalRow(MessageLength);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
speaker *
|
||||
|
@ -9210,7 +9253,7 @@ FreeReferences(_memory_book(ref_info) *References)
|
|||
rc
|
||||
ProcessTimecode(buffers *CollationBuffers, neighbourhood *N, string Filepath, memory_book *Strings,
|
||||
menu_buffers *MenuBuffers, index_buffers *IndexBuffers, player_buffers *PlayerBuffers,
|
||||
medium *DefaultMedium, speakers *Speakers, string Author,
|
||||
medium *DefaultMedium, speakers *Speakers, person *Host, string Author,
|
||||
_memory_book(ref_info) *ReferencesArray,
|
||||
bool *HasQuoteMenu, bool *HasReferenceMenu, bool *HasFilterMenu, bool *RequiresCineraJS,
|
||||
int *QuoteIdentifier, int *RefIdentifier,
|
||||
|
@ -9247,7 +9290,7 @@ ProcessTimecode(buffers *CollationBuffers, neighbourhood *N, string Filepath, me
|
|||
CopyStringToBuffer(&IndexBuffers->Class,
|
||||
" class=\"marker");
|
||||
|
||||
speaker *Speaker = GetSpeaker(&Speakers->Speakers, Anno->author ? Wrap0(Anno->author) : CurrentProject->StreamUsername.Length > 0 ? CurrentProject->StreamUsername : CurrentProject->Owner->ID);
|
||||
speaker *Speaker = GetSpeaker(&Speakers->Speakers, Anno->author ? Wrap0(Anno->author) : CurrentProject->StreamUsername.Length > 0 ? CurrentProject->StreamUsername : Host->ID);
|
||||
if(!IsCategorisedAFK(Anno))
|
||||
{
|
||||
if(Speakers->Speakers.ItemCount > 1 && Speaker && !IsCategorisedAuthored(Anno))
|
||||
|
@ -9617,12 +9660,46 @@ ProcessTimecode(buffers *CollationBuffers, neighbourhood *N, string Filepath, me
|
|||
return Result;
|
||||
}
|
||||
|
||||
string
|
||||
GetNumberFromHMMLBaseFilename(string ProjectID, string HMMLBaseFilename)
|
||||
{
|
||||
// TODO(matt): That rigorous notion of numbering, goddammit?!
|
||||
string Result = {};
|
||||
if(HMMLBaseFilename.Length > ProjectID.Length)
|
||||
{
|
||||
Result = TrimString(HMMLBaseFilename, ProjectID.Length, 0);
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
rc
|
||||
HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseFilename, neighbourhood *N)
|
||||
{
|
||||
MEM_TEST_TOP("HMMLToBuffers");
|
||||
rc Result = RC_SUCCESS;
|
||||
|
||||
RewindCollationBuffers(CollationBuffers);
|
||||
Clear(CollationBuffers->Custom0, sizeof(CollationBuffers->Custom0));
|
||||
Clear(CollationBuffers->Custom1, sizeof(CollationBuffers->Custom1));
|
||||
Clear(CollationBuffers->Custom2, sizeof(CollationBuffers->Custom2));
|
||||
Clear(CollationBuffers->Custom3, sizeof(CollationBuffers->Custom3));
|
||||
Clear(CollationBuffers->Custom4, sizeof(CollationBuffers->Custom4));
|
||||
Clear(CollationBuffers->Custom5, sizeof(CollationBuffers->Custom5));
|
||||
Clear(CollationBuffers->Custom6, sizeof(CollationBuffers->Custom6));
|
||||
Clear(CollationBuffers->Custom7, sizeof(CollationBuffers->Custom7));
|
||||
Clear(CollationBuffers->Custom8, sizeof(CollationBuffers->Custom8));
|
||||
Clear(CollationBuffers->Custom9, sizeof(CollationBuffers->Custom9));
|
||||
Clear(CollationBuffers->Custom10, sizeof(CollationBuffers->Custom10));
|
||||
Clear(CollationBuffers->Custom11, sizeof(CollationBuffers->Custom11));
|
||||
Clear(CollationBuffers->Custom12, sizeof(CollationBuffers->Custom12));
|
||||
Clear(CollationBuffers->Custom13, sizeof(CollationBuffers->Custom13));
|
||||
Clear(CollationBuffers->Custom14, sizeof(CollationBuffers->Custom14));
|
||||
Clear(CollationBuffers->Custom15, sizeof(CollationBuffers->Custom15));
|
||||
Clear(CollationBuffers->Title, sizeof(CollationBuffers->Title));
|
||||
Clear(CollationBuffers->URLPlayer, sizeof(CollationBuffers->URLPlayer));
|
||||
Clear(CollationBuffers->URLSearch, sizeof(CollationBuffers->URLSearch));
|
||||
Clear(CollationBuffers->VODPlatform, sizeof(CollationBuffers->VODPlatform));
|
||||
|
||||
// TODO(matt): A "MakeString0OnStack()" sort of function?
|
||||
// NOTE(matt): Stack-string
|
||||
int NullTerminationBytes = 1;
|
||||
|
@ -9656,30 +9733,11 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
// NOTE(matt): WorkingThis.Size > 0 means that this entry was previously processed as non-private. Would we rather
|
||||
// reregister such an entry as newly private? This test lets us avoid calling VideoIsPrivate() for all
|
||||
// entries, on every cinera invocation, when !CurrentProject->IgnorePrivacy
|
||||
if(N->WorkingThis.Size > 0 || CurrentProject->IgnorePrivacy || !VideoIsPrivate(HMML.metadata.id))
|
||||
{
|
||||
RewindCollationBuffers(CollationBuffers);
|
||||
Clear(CollationBuffers->Custom0, sizeof(CollationBuffers->Custom0));
|
||||
Clear(CollationBuffers->Custom1, sizeof(CollationBuffers->Custom1));
|
||||
Clear(CollationBuffers->Custom2, sizeof(CollationBuffers->Custom2));
|
||||
Clear(CollationBuffers->Custom3, sizeof(CollationBuffers->Custom3));
|
||||
Clear(CollationBuffers->Custom4, sizeof(CollationBuffers->Custom4));
|
||||
Clear(CollationBuffers->Custom5, sizeof(CollationBuffers->Custom5));
|
||||
Clear(CollationBuffers->Custom6, sizeof(CollationBuffers->Custom6));
|
||||
Clear(CollationBuffers->Custom7, sizeof(CollationBuffers->Custom7));
|
||||
Clear(CollationBuffers->Custom8, sizeof(CollationBuffers->Custom8));
|
||||
Clear(CollationBuffers->Custom9, sizeof(CollationBuffers->Custom9));
|
||||
Clear(CollationBuffers->Custom10, sizeof(CollationBuffers->Custom10));
|
||||
Clear(CollationBuffers->Custom11, sizeof(CollationBuffers->Custom11));
|
||||
Clear(CollationBuffers->Custom12, sizeof(CollationBuffers->Custom12));
|
||||
Clear(CollationBuffers->Custom13, sizeof(CollationBuffers->Custom13));
|
||||
Clear(CollationBuffers->Custom14, sizeof(CollationBuffers->Custom14));
|
||||
Clear(CollationBuffers->Custom15, sizeof(CollationBuffers->Custom15));
|
||||
Clear(CollationBuffers->Title, sizeof(CollationBuffers->Title));
|
||||
Clear(CollationBuffers->URLPlayer, sizeof(CollationBuffers->URLPlayer));
|
||||
Clear(CollationBuffers->URLSearch, sizeof(CollationBuffers->URLSearch));
|
||||
Clear(CollationBuffers->VODPlatform, sizeof(CollationBuffers->VODPlatform));
|
||||
|
||||
if(N->WorkingThis.Size > 0 || CurrentProject->IgnorePrivacy || !VideoIsPrivate(CurrentProject->VODPlatform, HMML.metadata.id))
|
||||
{
|
||||
// TODO(matt): Do a catch-all function that checks for missing info at the head, such as everything from here
|
||||
// to the loop and additionally an indexer
|
||||
if(BaseFilename.Length > MAX_BASE_FILENAME_LENGTH)
|
||||
{
|
||||
IndexingErrorSizing(&FilepathL, 0, "Base filename", BaseFilename, MAX_BASE_FILENAME_LENGTH);
|
||||
|
@ -9702,15 +9760,24 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
Title = Wrap0(HMML.metadata.title);
|
||||
}
|
||||
|
||||
if(!HMML.metadata.member)
|
||||
person *Host = CurrentProject->Owner;
|
||||
if(HMML.metadata.member)
|
||||
{
|
||||
IndexingError(&FilepathL, 0, S_ERROR, "The [video] node lacks a \"member\"", 0);
|
||||
Result = RC_ERROR_HMML;
|
||||
Host = GetPersonFromConfig(Wrap0(HMML.metadata.member));
|
||||
if(!Host && CurrentProject->Owner)
|
||||
{
|
||||
fprintf(stderr, "Falling back to the owner set in the config: ");
|
||||
PrintStringCN(CS_MAGENTA_BOLD, CurrentProject->Owner->ID, FALSE, TRUE);
|
||||
Host = CurrentProject->Owner;
|
||||
}
|
||||
}
|
||||
else if(!GetPersonFromConfig(Wrap0(HMML.metadata.member)))
|
||||
|
||||
if(!Host)
|
||||
{
|
||||
ErrorCredentials(FilepathL, Wrap0(HMML.metadata.member), R_HOST);
|
||||
IndexingError(&FilepathL, 0, S_ERROR, "No known owner set in the config, or member in the [video] node", 0);
|
||||
Result = RC_ERROR_HMML;
|
||||
//ErrorCredentials(FilepathL, Wrap0(HMML.metadata.member), R_HOST);
|
||||
//Result = RC_ERROR_HMML;
|
||||
}
|
||||
|
||||
if(!HMML.metadata.id)
|
||||
|
@ -9928,14 +9995,14 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
" <div class=\"markers\">\n");
|
||||
|
||||
bool RequiresCineraJS = FALSE;
|
||||
Result = BuildCredits(FilepathL, &MenuBuffers.Credits, &HMML.metadata, &Speakers, &RequiresCineraJS);
|
||||
Result = BuildCredits(FilepathL, &MenuBuffers.Credits, &HMML.metadata, Host, &Speakers, &RequiresCineraJS);
|
||||
if(Result == RC_SUCCESS)
|
||||
{
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "name: \"");
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "%.*s", (int)OutputLocation.Length, OutputLocation.Base);
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "location: \"%.*s\"\n", (int)OutputLocation.Length, OutputLocation.Base);
|
||||
string Number = GetNumberFromHMMLBaseFilename(Wrap0i(N->Project->ID, sizeof(N->Project->ID)), BaseFilename);
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "number: \"%.*s\"\n", (int)Number.Length, Number.Base);
|
||||
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\"\n"
|
||||
"title: \"");
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "title: \"");
|
||||
CopyStringToBufferNoFormat(&CollationBuffers->SearchEntry, Wrap0(HMML.metadata.title));
|
||||
CopyStringToBuffer(&CollationBuffers->SearchEntry, "\"\n"
|
||||
"markers:\n");
|
||||
|
@ -9964,12 +10031,12 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
if(Anno->quote.author) { Author = Wrap0(Anno->quote.author); }
|
||||
else if(HMML.metadata.stream_username) { Author = Wrap0(HMML.metadata.stream_username); }
|
||||
else if(CurrentProject->StreamUsername.Length > 0) { Author = CurrentProject->StreamUsername; }
|
||||
else { Author = CurrentProject->Owner->ID; }
|
||||
else { Author = Host->ID; }
|
||||
|
||||
/* */ MEM_TEST_MID("HMMLToBuffers");
|
||||
/* +MEM */ Result = ProcessTimecode(CollationBuffers, N, Wrap0(Filepath), &Strings,
|
||||
/* */ &MenuBuffers, &IndexBuffers, &PlayerBuffers,
|
||||
/* */ DefaultMedium, &Speakers, Author, &ReferencesArray,
|
||||
/* */ DefaultMedium, &Speakers, Host, Author, &ReferencesArray,
|
||||
/* */ &HasQuoteMenu, &HasReferenceMenu, &HasFilterMenu, &RequiresCineraJS,
|
||||
/* */ &QuoteIdentifier, &RefIdentifier,
|
||||
/* */ &Topics, &Media,
|
||||
|
@ -10167,7 +10234,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
}
|
||||
|
||||
CopyStringToBuffer(&PlayerBuffers.Menus,
|
||||
" <div class=\"help\">\n"
|
||||
" <div class=\"cineraHelp\">\n"
|
||||
" <span>?</span>\n"
|
||||
" <div class=\"help_container\">\n"
|
||||
" <span class=\"help_key\">?</span><h1>Keyboard Navigation</h1>\n"
|
||||
|
@ -10347,7 +10414,8 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesPlayer,
|
||||
"<meta charset=\"UTF-8\">\n"
|
||||
" <meta name=\"generator\" content=\"Cinera %d.%d.%d\">\n",
|
||||
" <meta name=\"generator\" content=\"Cinera %d.%d.%d\">\n"
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n",
|
||||
CINERA_APP_VERSION.Major,
|
||||
CINERA_APP_VERSION.Minor,
|
||||
CINERA_APP_VERSION.Patch);
|
||||
|
@ -10362,7 +10430,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
for(int i = 0; i < Topics.ItemCount; ++i)
|
||||
{
|
||||
category_info *This = GetPlaceInBook(&Topics, i);
|
||||
if(StringsMatch(This->Marker, Wrap0("nullTopic")))
|
||||
if(!StringsMatch(This->Marker, Wrap0("nullTopic")))
|
||||
{
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesPlayer, "%.*s, ", (int)This->Marker.Length, This->Marker.Base);
|
||||
}
|
||||
|
@ -10477,7 +10545,7 @@ HMMLToBuffers(buffers *CollationBuffers, template *BespokeTemplate, string BaseF
|
|||
CopyStringToBuffer(&PlayerBuffers.Script,
|
||||
"\"></script>");
|
||||
|
||||
CopyStringToBuffer(&CollationBuffers->Player, "<div>\n"
|
||||
CopyStringToBuffer(&CollationBuffers->Player, "<div class=\"cinera\">\n"
|
||||
" ");
|
||||
CopyLandmarkedBuffer(&CollationBuffers->Player, &PlayerBuffers.Menus, 0, PAGE_PLAYER);
|
||||
CopyStringToBuffer(&CollationBuffers->Player, "\n"
|
||||
|
@ -10555,12 +10623,16 @@ typedef struct
|
|||
html_element HTMLElements[] =
|
||||
{
|
||||
{ "a", FALSE },
|
||||
{ "br", TRUE },
|
||||
{ "div", FALSE },
|
||||
{ "h1", FALSE },
|
||||
{ "h2", FALSE },
|
||||
{ "img", TRUE },
|
||||
{ "input", TRUE },
|
||||
{ "label", FALSE },
|
||||
{ "li", FALSE },
|
||||
{ "nav", FALSE },
|
||||
{ "p", FALSE },
|
||||
{ "script", FALSE },
|
||||
{ "span", FALSE },
|
||||
{ "ul", FALSE },
|
||||
|
@ -10569,12 +10641,16 @@ html_element HTMLElements[] =
|
|||
typedef enum
|
||||
{
|
||||
NODE_A,
|
||||
NODE_BR,
|
||||
NODE_DIV,
|
||||
NODE_H1,
|
||||
NODE_H2,
|
||||
NODE_IMG,
|
||||
NODE_INPUT,
|
||||
NODE_LABEL,
|
||||
NODE_LI,
|
||||
NODE_NAV,
|
||||
NODE_P,
|
||||
NODE_SCRIPT,
|
||||
NODE_SPAN,
|
||||
NODE_UL,
|
||||
|
@ -11619,10 +11695,9 @@ InsertIntoDB(neighbourhood *N, buffers *CollationBuffers, template *BespokeTempl
|
|||
CycleFile(&DB.File);
|
||||
}
|
||||
|
||||
string EntryTitle = Wrap0(CollationBuffers->Title);
|
||||
|
||||
if(!VideoIsPrivate || !RecheckingPrivacy)
|
||||
{
|
||||
string EntryTitle = Wrap0(CollationBuffers->Title);
|
||||
LogEdit(EditType, CurrentProject->Lineage, BaseFilename, &EntryTitle, VideoIsPrivate);
|
||||
PrintEdit(EditType, CurrentProject->Lineage, BaseFilename, &EntryTitle, VideoIsPrivate, TRUE);
|
||||
}
|
||||
|
@ -12825,7 +12900,7 @@ GenerateFilterOfProjectAndChildren(buffer *Filter, db_header_project *StoredP, p
|
|||
if(!TopLevel || StoredP->EntryCount > 0)
|
||||
{
|
||||
OpenNodeNewLine(Filter, &Filter->IndentLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(Filter, Wrap0(" class=\"cineraFilterProject\" data-baseURL=\""));
|
||||
AppendStringToBuffer(Filter, Wrap0(" class=\"cineraMenuItem cineraFilterProject\" data-baseURL=\""));
|
||||
AppendStringToBuffer(Filter, P->BaseURL);
|
||||
AppendStringToBuffer(Filter, Wrap0("\" data-searchLocation=\""));
|
||||
AppendStringToBuffer(Filter, P->SearchLocation);
|
||||
|
@ -12872,6 +12947,8 @@ GenerateIndexOfProjectAndChildren(buffer *Index, db_header_project *StoredP, pro
|
|||
AppendStringToBuffer(Index, P->SearchLocation);
|
||||
AppendStringToBuffer(Index, Wrap0("\" data-playerLocation=\""));
|
||||
AppendStringToBuffer(Index, P->PlayerLocation);
|
||||
AppendStringToBuffer(Index, Wrap0("\" data-unit=\""));
|
||||
AppendStringToBuffer(Index, P->Unit);
|
||||
AppendStringToBuffer(Index, Wrap0("\">"));
|
||||
|
||||
OpenNodeNewLine(Index, &Index->IndentLevel, NODE_DIV, 0);
|
||||
|
@ -12905,27 +12982,28 @@ GenerateIndexOfProjectAndChildren(buffer *Index, db_header_project *StoredP, pro
|
|||
|
||||
if(*StoredP->Unit)
|
||||
{
|
||||
// TODO(matt): That rigorous notion of numbering, goddammit?!
|
||||
string NumberL = TrimString(Wrap0i(Entry->HMMLBaseFilename, sizeof(Entry->HMMLBaseFilename)),
|
||||
P->ID.Length, 0);
|
||||
char Number[NumberL.Length + 1];
|
||||
ClearCopyStringNoFormat(Number, sizeof(Number), NumberL);
|
||||
|
||||
if(CurrentProject->NumberingScheme == NS_LINEAR)
|
||||
string NumberL = GetNumberFromHMMLBaseFilename(P->ID, Wrap0i(Entry->HMMLBaseFilename, sizeof(Entry->HMMLBaseFilename)));
|
||||
if(NumberL.Length > 0)
|
||||
{
|
||||
for(int i = 0; Number[i]; ++i)
|
||||
char Number[NumberL.Length + 1];
|
||||
ClearCopyStringNoFormat(Number, sizeof(Number), NumberL);
|
||||
|
||||
if(CurrentProject->NumberingScheme == NS_LINEAR)
|
||||
{
|
||||
if(Number[i] == '_')
|
||||
for(int i = 0; Number[i]; ++i)
|
||||
{
|
||||
Number[i] = '.';
|
||||
if(Number[i] == '_')
|
||||
{
|
||||
Number[i] = '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AppendStringToBuffer(Index, P->Unit);
|
||||
AppendStringToBuffer(Index, Wrap0(" "));
|
||||
AppendStringToBuffer(Index, Wrap0i(Number, sizeof(Number)));
|
||||
AppendStringToBuffer(Index, Wrap0(": "));
|
||||
AppendStringToBuffer(Index, P->Unit);
|
||||
AppendStringToBuffer(Index, Wrap0(" "));
|
||||
AppendStringToBuffer(Index, Wrap0i(Number, sizeof(Number)));
|
||||
AppendStringToBuffer(Index, Wrap0(": "));
|
||||
}
|
||||
}
|
||||
|
||||
// HERE
|
||||
|
@ -13097,6 +13175,45 @@ GenerateThemeLinks(buffer *IncludesSearch, project *P)
|
|||
FreeBook(&UniqueThemes);
|
||||
}
|
||||
|
||||
void
|
||||
AppendHelpKeyToBuffer(buffer *B, uint32_t *IndentationLevel, string Key, bool Available)
|
||||
{
|
||||
OpenNodeNewLine(B, IndentationLevel, NODE_SPAN, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"help_key"));
|
||||
if(!Available)
|
||||
{
|
||||
AppendStringToBuffer(B, Wrap0(" unavailable"));
|
||||
}
|
||||
AppendStringToBuffer(B, Wrap0("\">"));
|
||||
AppendStringToBuffer(B, Key);
|
||||
CloseNode(B, IndentationLevel, NODE_SPAN);
|
||||
}
|
||||
|
||||
void
|
||||
AppendHelpKeyToBufferNewLine(buffer *B, uint32_t *IndentationLevel, string Key, bool Available)
|
||||
{
|
||||
AppendHelpKeyToBuffer(B, IndentationLevel, Key, Available);
|
||||
OpenNodeC(B, IndentationLevel, NODE_BR, 0);
|
||||
}
|
||||
|
||||
void
|
||||
AppendHelpKeyAndTextToBuffer(buffer *B, uint32_t *IndentationLevel, string Key, string Text, bool Available)
|
||||
{
|
||||
AppendHelpKeyToBuffer(B, IndentationLevel, Key, Available);
|
||||
AppendStringToBuffer(B, Wrap0(" "));
|
||||
|
||||
OpenNodeNewLine(B, IndentationLevel, NODE_SPAN, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"help_text"));
|
||||
if(!Available)
|
||||
{
|
||||
AppendStringToBuffer(B, Wrap0(" unavailable"));
|
||||
}
|
||||
AppendStringToBuffer(B, Wrap0("\">"));
|
||||
AppendStringToBuffer(B, Text);
|
||||
CloseNode(B, IndentationLevel, NODE_SPAN);
|
||||
AppendStringToBuffer(B, Wrap0("\n"));
|
||||
}
|
||||
|
||||
int
|
||||
SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P, string Theme, bool RequiresCineraJS) // NOTE(matt): This guy malloc's CollationBuffers->Search
|
||||
{
|
||||
|
@ -13134,6 +13251,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"<meta charset=\"UTF-8\">\n"
|
||||
" <meta name=\"generator\" content=\"Cinera %d.%d.%d\">\n"
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n"
|
||||
"\n"
|
||||
" <link rel=\"stylesheet\" type=\"text/css\" href=\"%.*s",
|
||||
CINERA_APP_VERSION.Major,
|
||||
|
@ -13159,38 +13277,54 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"\">");
|
||||
|
||||
asset *JSSearch = GetAsset(Wrap0(BuiltinAssets[ASSET_JS_SEARCH].Filename), ASSET_JS);
|
||||
ConstructResolvedAssetURL(&URL, JSSearch, PAGE_SEARCH);
|
||||
|
||||
uint32_t IndentationLevel = 1;
|
||||
++IndentationLevel;
|
||||
|
||||
buffer Script = {};
|
||||
Script.ID = BID_SCRIPT;
|
||||
OpenNodeNewLine(&Script, &IndentationLevel, NODE_SCRIPT, 0);
|
||||
AppendStringToBuffer(&Script, Wrap0(" type=\"text/javascript\" src=\""));
|
||||
AppendStringToBuffer(&Script, Wrap0i(URL.Location, URL.Ptr - URL.Location));
|
||||
DeclaimBuffer(&URL);
|
||||
PushAssetLandmark(&Script, JSSearch, PAGE_SEARCH, TRUE);
|
||||
AppendStringToBuffer(&Script, Wrap0("\">"));
|
||||
CloseNode(&Script, &IndentationLevel, NODE_SCRIPT);
|
||||
|
||||
bool SearchRequired = FALSE;
|
||||
|
||||
//IndentBuffer(&CollationBuffers->Search, ++IndentationLevel);
|
||||
|
||||
buffer *B = &CollationBuffers->Search;
|
||||
OpenNode(B, &IndentationLevel, NODE_DIV, "cineraIndexControl");
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, "cineraIndex");
|
||||
AppendStringToBuffer(B, Wrap0(" class=\""));
|
||||
AppendStringToBuffer(B, Theme);
|
||||
AppendStringToBuffer(B, Wrap0("\">"));
|
||||
OpenNodeC(B, &IndentationLevel, NODE_DIV, "cineraIndexControl");
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, "cineraIndexSort");
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenu cineraMenuTitle ViewSettings\">"));
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_SPAN, 0);
|
||||
AppendStringToBuffer(B, Wrap0("Settings"));
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_SPAN);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuContainer\">"));
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuItem sort\">"));
|
||||
AppendStringToBuffer(B, Wrap0("Sort: Old to New ⏶"));
|
||||
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuItem view\">"));
|
||||
AppendStringToBuffer(B, Wrap0("View: Grid"));
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuItem anim\">"));
|
||||
AppendStringToBuffer(B, Wrap0("Animations: ✔"));
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuItem save\">"));
|
||||
AppendStringToBuffer(B, Wrap0("Save Settings: ✔"));
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraMenuContainer
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraMenu ViewSettings
|
||||
|
||||
bool FilterRequired = FALSE;
|
||||
if(StoredP)
|
||||
{
|
||||
|
@ -13221,7 +13355,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraIndexFilter\">"));
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenu cineraMenuTitle IndexFilter\">"));
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_SPAN, 0);
|
||||
|
||||
|
@ -13237,7 +13371,7 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
CloseNode(B, &IndentationLevel, NODE_SPAN);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"filter_container\">"));
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraMenuContainer\">"));
|
||||
}
|
||||
|
||||
// NOTE(matt): What I think the rules should be are:
|
||||
|
@ -13271,8 +13405,8 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
{
|
||||
AppendLandmarkedBuffer(B, &Filter, PAGE_SEARCH);
|
||||
FreeBuffer(&Filter);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraMenuContainer
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraMenu IndexFilter
|
||||
}
|
||||
|
||||
asset *JSCineraPre = GetAsset(Wrap0(BuiltinAssets[ASSET_JS_CINERA_PRE].Filename), ASSET_JS);
|
||||
|
@ -13298,6 +13432,26 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
"\" defer></script>");
|
||||
}
|
||||
|
||||
asset *JSSearchPre = GetAsset(Wrap0(BuiltinAssets[ASSET_JS_SEARCH_PRE].Filename), ASSET_JS);
|
||||
ConstructResolvedAssetURL(&URL, JSSearchPre, PAGE_SEARCH);
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"\n <script type=\"text/javascript\" src=\"%s",
|
||||
URL.Location);
|
||||
DeclaimBuffer(&URL);
|
||||
PushAssetLandmark(&CollationBuffers->IncludesSearch, JSSearchPre, PAGE_SEARCH, 0);
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"\"></script>");
|
||||
|
||||
asset *JSSearchPost = GetAsset(Wrap0(BuiltinAssets[ASSET_JS_SEARCH_POST].Filename), ASSET_JS);
|
||||
ConstructResolvedAssetURL(&URL, JSSearchPost, PAGE_SEARCH);
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"\n <script type=\"text/javascript\" src=\"%s",
|
||||
URL.Location);
|
||||
DeclaimBuffer(&URL);
|
||||
PushAssetLandmark(&CollationBuffers->IncludesSearch, JSSearchPost, PAGE_SEARCH, 0);
|
||||
CopyStringToBuffer(&CollationBuffers->IncludesSearch,
|
||||
"\" defer></script>");
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraQueryContainer\">"));
|
||||
|
||||
|
@ -13320,10 +13474,82 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
IndentBuffer(B, IndentationLevel);
|
||||
AppendStringToBuffer(B, Wrap0("Downloading data..."));
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // spinner
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // inputContainer
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraQueryContainer
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraHelp\">"));
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_SPAN, 0);
|
||||
AppendStringToBuffer(B, Wrap0("?"));
|
||||
CloseNode(B, &IndentationLevel, NODE_SPAN);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"help_container\">"));
|
||||
|
||||
AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("?"), TRUE);
|
||||
OpenNodeC(B, &IndentationLevel, NODE_H1, 0);
|
||||
AppendStringToBuffer(B, Wrap0("Keyboard Navigation"));
|
||||
CloseNode(B, &IndentationLevel, NODE_H1);
|
||||
|
||||
OpenNodeC(B, &IndentationLevel, NODE_H2, 0);
|
||||
AppendStringToBuffer(B, Wrap0("Grid Traversal"));
|
||||
CloseNode(B, &IndentationLevel, NODE_H2);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("h"), Wrap0("Shift leftwards"), TRUE);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("k"), Wrap0("Ascend (zoom out)"), TRUE);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("l"), Wrap0("Shift rightwards"), TRUE);
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_BR, 0);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"help_paragraph\">"));
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"key_block\">"));
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("1"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("q"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("a"), TRUE);
|
||||
AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("z"), TRUE);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("2"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("w"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("s"), TRUE);
|
||||
AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("x"), TRUE);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("3"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("e"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("d"), TRUE);
|
||||
AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("c"), TRUE);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("4"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("r"), TRUE);
|
||||
AppendHelpKeyToBufferNewLine(B, &IndentationLevel, Wrap0("f"), TRUE);
|
||||
AppendHelpKeyToBuffer(B, &IndentationLevel, Wrap0("v"), TRUE);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // key_block
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // help_paragraph
|
||||
|
||||
OpenNodeC(B, &IndentationLevel, NODE_H2, 0);
|
||||
AppendStringToBuffer(B, Wrap0("Settings"));
|
||||
CloseNode(B, &IndentationLevel, NODE_H2);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("t"), Wrap0("Toggle sort order"), TRUE);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("y"), Wrap0("Toggle view style"), TRUE);
|
||||
AppendHelpKeyAndTextToBuffer(B, &IndentationLevel, Wrap0("m"), Wrap0("Toggle animations"), TRUE);
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // help_container
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraHelp
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraIndexControl
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, "cineraResultsSummary");
|
||||
|
||||
|
@ -13340,17 +13566,50 @@ SearchToBuffer(buffers *CollationBuffers, db_header_project *StoredP, project *P
|
|||
|
||||
AppendStringToBuffer(B, Wrap0("\n"));
|
||||
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, "cineraIndex");
|
||||
OpenNodeCNewLine(B, &IndentationLevel, NODE_DIV, "cineraIndexList");
|
||||
|
||||
|
||||
AppendLandmarkedBuffer(B, &Index, PAGE_SEARCH);
|
||||
FreeBuffer(&Index);
|
||||
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV);
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraIndexList
|
||||
|
||||
AppendLandmarkedBuffer(B, &Script, PAGE_SEARCH);
|
||||
FreeBuffer(&Script);
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraIndexGridContainer\">"));
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraTraversalContainer\">"));
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraTraversal\">"));
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraButton prev\">"));
|
||||
OpenNodeC(B, &IndentationLevel, NODE_P, 0);
|
||||
AppendStringToBuffer(B, Wrap0("←"));
|
||||
CloseNode(B, &IndentationLevel, NODE_P);
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraButton ascension\">"));
|
||||
OpenNodeC(B, &IndentationLevel, NODE_P, 0);
|
||||
AppendStringToBuffer(B, Wrap0("↑"));
|
||||
CloseNode(B, &IndentationLevel, NODE_P);
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
OpenNodeNewLine(B, &IndentationLevel, NODE_DIV, 0);
|
||||
AppendStringToBuffer(B, Wrap0(" class=\"cineraButton next\">"));
|
||||
OpenNodeC(B, &IndentationLevel, NODE_P, 0);
|
||||
AppendStringToBuffer(B, Wrap0("→"));
|
||||
CloseNode(B, &IndentationLevel, NODE_P);
|
||||
CloseNode(B, &IndentationLevel, NODE_DIV);
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraTraversal
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraTraversalContainer
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraIndexGridContainer
|
||||
|
||||
CloseNodeNewLine(B, &IndentationLevel, NODE_DIV); // cineraIndex
|
||||
|
||||
if(!SearchRequired) { return RC_NOOP; }
|
||||
else { return RC_SUCCESS; }
|
||||
|
|
|
@ -58,7 +58,7 @@ nav.cineraNavDropdown .cineraNavTitle {
|
|||
nav.cineraNavDropdown ul.cineraNavHorizontal {
|
||||
display: none;
|
||||
width: 100%;
|
||||
z-index: 8;
|
||||
z-index: 4096;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
@ -85,12 +85,124 @@ ul.cineraNavPlain li.current > a {
|
|||
|
||||
/* Index */
|
||||
|
||||
#cineraIndexControl {
|
||||
#cineraIndex
|
||||
{
|
||||
display: flex;
|
||||
margin: 16px auto;
|
||||
max-width: 1024px;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexControl
|
||||
{
|
||||
display: flex;
|
||||
position: -webkit-sticky;
|
||||
position: sticky;
|
||||
top: 0px;
|
||||
z-index: 64;
|
||||
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
padding: 8px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Portrait
|
||||
{
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Landscape.Left
|
||||
{
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Landscape.Right
|
||||
{
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Landscape .cineraTraversal
|
||||
{
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Landscape .cineraTraversal .cineraButton.prev
|
||||
{
|
||||
order: 1;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexGridContainer.Landscape .cineraTraversal .cineraButton.next
|
||||
{
|
||||
order: 2;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraTraversal .cineraButton
|
||||
{
|
||||
/* TODO(matt): Do the cineraTraversal as a flex box, to auto-size these buttons? */
|
||||
height: 42px;
|
||||
width: 42px;
|
||||
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#cineraIndex.anim .cineraTraversal,
|
||||
#cineraIndex.anim .cineraTraversal * p
|
||||
{
|
||||
transition: transform .32s;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraTraversalContainer
|
||||
{
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraTraversal
|
||||
{
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
#cineraIndex.reversed .cineraTraversal
|
||||
{
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
#cineraIndex .cineraTraversal * p
|
||||
{
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
#cineraIndex.reversed .cineraTraversal .ascension p
|
||||
{
|
||||
transform: rotate(-180deg);
|
||||
}
|
||||
|
||||
#cineraIndex.reversed .cineraTraversal .prev p,
|
||||
#cineraIndex.reversed .cineraTraversal .next p
|
||||
{
|
||||
transform: rotate(-360deg);
|
||||
}
|
||||
|
||||
#cineraIndex .cineraTraversal .next.ascension p
|
||||
{
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
#cineraIndex.reversed .cineraTraversal .next.ascension p
|
||||
{
|
||||
transform: rotate(-315deg);
|
||||
}
|
||||
|
||||
.cineraFilterProject .cineraText,
|
||||
|
@ -99,15 +211,30 @@ ul.cineraNavPlain li.current > a {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.cineraIndexFilter {
|
||||
.cineraMenu.cineraMenuTitle {
|
||||
padding: 10px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.cineraIndexFilter .filter_container
|
||||
.cineraMenuContainer
|
||||
{
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
z-index: 64;
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
|
||||
border: 1px solid;
|
||||
border-top: none;
|
||||
}
|
||||
|
||||
.cineraMenuContainer.visible
|
||||
{
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cineraFilterProject,
|
||||
|
@ -120,7 +247,7 @@ ul.cineraNavPlain li.current > a {
|
|||
}
|
||||
|
||||
.cineraIndexProject .cineraProjectTitle,
|
||||
.cineraFilterProject
|
||||
.cineraMenuItem
|
||||
{
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
|
@ -130,7 +257,6 @@ ul.cineraNavPlain li.current > a {
|
|||
flex-grow: 1;
|
||||
padding-left: 16px;
|
||||
display: flex;
|
||||
flex-direction: horizontal;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
@ -141,19 +267,21 @@ ul.cineraNavPlain li.current > a {
|
|||
}
|
||||
|
||||
.cineraQueryContainer .inputContainer {
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
position: relative;
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
.cineraQueryContainer #query {
|
||||
width: 100%;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.cineraQueryContainer .inputContainer .spinner {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
right: 5px;
|
||||
color: black;
|
||||
color: #000000;
|
||||
height: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
@ -163,7 +291,7 @@ ul.cineraNavPlain li.current > a {
|
|||
}
|
||||
|
||||
#cineraResults,
|
||||
#cineraIndex {
|
||||
#cineraIndexList {
|
||||
margin: 0 auto;
|
||||
max-width: 800px;
|
||||
}
|
||||
|
@ -173,22 +301,94 @@ ul.cineraNavPlain li.current > a {
|
|||
flex-flow: column;
|
||||
}
|
||||
|
||||
#cineraIndexControl #cineraIndexSort {
|
||||
padding: 4px;
|
||||
#cineraIndexList .cineraIndexEntries {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#cineraIndexControl #cineraIndexSort,
|
||||
#cineraIndexControl .cineraIndexFilter .filter_container {
|
||||
cursor: pointer;
|
||||
#cineraIndex #cineraIndexGrid
|
||||
{
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
perspective-origin: center;
|
||||
-webkit-perspective-origin: center;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButtons
|
||||
{
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
grid-gap: 2px;
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraButton
|
||||
{
|
||||
border: 1px solid;
|
||||
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
|
||||
flex-direction: column;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
#cineraIndex .cineraIndexEntries {
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision
|
||||
{
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
backface-visibility: hidden;
|
||||
-webkit-backface-visibility: hidden;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision .head-item,
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision .tail-item
|
||||
{
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision.leaf
|
||||
{
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision.leaf a
|
||||
{
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision.leaf a:hover {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision .head-item,
|
||||
#cineraIndex.reversed #cineraIndexGrid .cineraButton.subdivision .tail-item
|
||||
{
|
||||
align-items: flex-start;
|
||||
justify-content: flex-start;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
#cineraIndex #cineraIndexGrid .cineraButton.subdivision .tail-item,
|
||||
#cineraIndex.reversed #cineraIndexGrid .cineraButton.subdivision .head-item
|
||||
{
|
||||
align-items: flex-end;
|
||||
justify-content: flex-end;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#cineraIndexList.hidden,
|
||||
#cineraIndex .cineraIndexGridContainer.hidden
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
#cineraResults .dayContainer {
|
||||
|
@ -203,7 +403,7 @@ ul.cineraNavPlain li.current > a {
|
|||
line-height: 16px;
|
||||
padding: 5px;
|
||||
vertical-align: top;
|
||||
width: 200px;
|
||||
max-width: 200px;
|
||||
}
|
||||
|
||||
.cineraIndexEntries div a {
|
||||
|
@ -243,36 +443,6 @@ ul.cineraNavPlain li.current > a {
|
|||
display: none;
|
||||
}
|
||||
|
||||
@media (max-width: 720px), (max-height: 512px)
|
||||
{
|
||||
#cineraIndexControl {
|
||||
margin: 4px auto;
|
||||
}
|
||||
|
||||
#cineraIndexControl,
|
||||
#cineraResultsSummary {
|
||||
font-size: 64%;
|
||||
}
|
||||
|
||||
#cineraResults .dayContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#cineraResults .dayContainer .dayName {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#cineraResults .dayContainer .markerList {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.cineraIndexEntries div a {
|
||||
font-size: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
/* Player */
|
||||
|
||||
/* Player / Structure */
|
||||
|
@ -285,7 +455,7 @@ ul.cineraNavPlain li.current > a {
|
|||
text-decoration: none;
|
||||
}
|
||||
|
||||
.cineraMenus > *:not(.views),
|
||||
.cineraMenus > *:not(.views, .cineraHelp),
|
||||
.cineraMenus > .menu > .refs .ref,
|
||||
.cineraMenus > .menu > .view,
|
||||
.cineraMenus > .menu > .views_container .view,
|
||||
|
@ -299,7 +469,14 @@ ul.cineraNavPlain li.current > a {
|
|||
|
||||
.cineraMenus > .menu {
|
||||
position: relative;
|
||||
align-self: center;
|
||||
min-height: 1em;
|
||||
min-width: 1em;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu.filter.responsible,
|
||||
|
@ -312,67 +489,7 @@ ul.cineraNavPlain li.current > a {
|
|||
animation-iteration-count: 1;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_key {
|
||||
font-family: Inconsolata;
|
||||
font-size: 16px;
|
||||
border: 1px solid;
|
||||
display: inline-block;
|
||||
background-color: #111; /* Per project */
|
||||
border-radius: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
padding: 4px;
|
||||
line-height: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_key.word {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_key.modifer {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_key.unavailable,
|
||||
.cineraMenus .help .help_container .help_text.unavailable,
|
||||
.cineraMenus .help .help_container h2 .unavailable {
|
||||
opacity: 0.32;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .key_block {
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: row;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_text {
|
||||
margin: 0 8px 0 2px;
|
||||
}
|
||||
|
||||
|
||||
.cineraMenus .help .help_container h1 {
|
||||
display: inline;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container h1:after {
|
||||
content: "\a";
|
||||
}
|
||||
|
||||
|
||||
.cineraMenus .help .help_container h2 {
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_paragraph {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cineraMenus > .help {
|
||||
.cineraHelp {
|
||||
cursor: pointer;
|
||||
border: 1px solid;
|
||||
border-radius: 4px;
|
||||
|
@ -387,32 +504,87 @@ ul.cineraNavPlain li.current > a {
|
|||
z-index: 64;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container .help_grid {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container {
|
||||
background-color: black; /* Per project */
|
||||
color: #EEE; /* Per project */
|
||||
.cineraHelp .help_container {
|
||||
background-color: #000000; /* Per project */
|
||||
color: #EEEEEE; /* Per project */
|
||||
display: none;
|
||||
font-weight: normal;
|
||||
line-height: 12px;
|
||||
opacity: 0.9;
|
||||
padding: 8px;
|
||||
position: fixed;
|
||||
right: 612px;
|
||||
top: 42px;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.cineraMenus .help .help_container.visible {
|
||||
.cineraHelp .help_container.visible {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#cineraIndexControl .cineraIndexFilter .filter_container
|
||||
{
|
||||
.cineraHelp .help_container .help_key {
|
||||
font-family: Inconsolata;
|
||||
font-size: 16px;
|
||||
border: 1px solid;
|
||||
border-top: none;
|
||||
display: inline-block;
|
||||
background-color: #111111; /* Per project */
|
||||
border-radius: 4px;
|
||||
height: 16px;
|
||||
width: 16px;
|
||||
padding: 4px;
|
||||
line-height: 16px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_key.word {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_key.modifer {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_key.unavailable,
|
||||
.cineraHelp .help_container .help_text.unavailable,
|
||||
.cineraHelp .help_container h2 .unavailable {
|
||||
opacity: 0.32;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .key_block {
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
flex-direction: row;
|
||||
margin: 8px;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_text {
|
||||
margin: 0 8px 0 2px;
|
||||
}
|
||||
|
||||
|
||||
.cineraHelp .help_container h1 {
|
||||
display: inline;
|
||||
margin-left: 4px;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container h1:after {
|
||||
content: "\a";
|
||||
}
|
||||
|
||||
|
||||
.cineraHelp .help_container h2 {
|
||||
font-size: 16px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_paragraph {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.cineraHelp .help_container .help_grid {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu .quotes_container,
|
||||
|
@ -430,11 +602,13 @@ ul.cineraNavPlain li.current > a {
|
|||
position: absolute;
|
||||
right: 0;
|
||||
top: 100%;
|
||||
z-index: 1;
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu .refs,
|
||||
.cineraMenus > .menu .link_container {
|
||||
.cineraMenus > .menu .filter_container,
|
||||
.cineraMenus > .menu .link_container,
|
||||
.cineraMenus > .menu .credits_container {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
|
@ -442,12 +616,9 @@ ul.cineraNavPlain li.current > a {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu .filter_container {
|
||||
min-width: 350px;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu .credits_container {
|
||||
min-width: 240px;
|
||||
.cineraMenus > .menu .sizing {
|
||||
z-index: -1;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.cineraMenus > .menu .visible {
|
||||
|
@ -639,7 +810,7 @@ ul.cineraNavPlain li.current > a {
|
|||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container {
|
||||
flex-shrink: 0;
|
||||
flex-shrink: 1;
|
||||
overflow-y: scroll;
|
||||
position: relative;
|
||||
}
|
||||
|
@ -651,6 +822,16 @@ ul.cineraNavPlain li.current > a {
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer {
|
||||
background-color: #000000;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .video_container {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > a.episodeMarker {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -683,7 +864,7 @@ ul.cineraNavPlain li.current > a {
|
|||
border-bottom: 1px solid;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
max-height: 320px;
|
||||
max-height: 320px; /* NOTE(matt): Required for the transition */
|
||||
transition: max-height .32s;
|
||||
}
|
||||
|
||||
|
@ -709,7 +890,7 @@ ul.cineraNavPlain li.current > a {
|
|||
font-size: 14px;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .markers .marker.skip {
|
||||
.cinera:not(.mobile) .cineraPlayerContainer .markers_container > .markers .marker.skip {
|
||||
max-height: 0;
|
||||
transition: max-height .32s;
|
||||
overflow: hidden;
|
||||
|
@ -781,97 +962,109 @@ ul.cineraNavPlain li.current > a {
|
|||
margin-right: 8px;
|
||||
}
|
||||
|
||||
@media (max-width: 720px), (max-height: 512px)
|
||||
{
|
||||
.cineraMenus .episode_name,
|
||||
.cineraMenus > .menu > .view,
|
||||
.cineraMenus > .menu > .views_container .view,
|
||||
.cineraMenus > .help,
|
||||
.markers_container > .episodeMarker div:nth-child(2),
|
||||
.markers_container > .episodeMarker div:nth-child(3),
|
||||
.markers_container > .markers .marker:not(.current) {
|
||||
display: none;
|
||||
}
|
||||
/* NOTE(matt): Mobile Style */
|
||||
|
||||
.cineraMenus {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cineraMenus .menu .quotes_container,
|
||||
.cineraMenus .menu .references_container,
|
||||
.cineraMenus .menu .filter_container,
|
||||
.cineraMenus .menu .link_container,
|
||||
.cineraMenus .menu .credits_container {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
max-height: 80%;
|
||||
max-width: 97%;
|
||||
}
|
||||
|
||||
|
||||
.cineraPlayerContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker {
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
|
||||
width: 456px;
|
||||
}
|
||||
|
||||
@media (max-width: 580px)
|
||||
{
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
|
||||
width: 320px;
|
||||
}
|
||||
|
||||
}
|
||||
@media (max-width: 450px)
|
||||
{
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
|
||||
width: 256px;
|
||||
}
|
||||
|
||||
}
|
||||
@media (max-width: 375px)
|
||||
{
|
||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent {
|
||||
width: 180px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.first,
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.prev,
|
||||
.cineraPlayerContainer .markers_container > .markers .marker,
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.last,
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.next {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.first,
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.prev {
|
||||
border-right: 3px double;
|
||||
}
|
||||
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.last,
|
||||
.cineraPlayerContainer .markers_container > .episodeMarker.next {
|
||||
border-left: 3px double;
|
||||
}
|
||||
#cineraIndex.mobile #cineraResults .dayContainer {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
#cineraIndex.mobile #cineraResults .dayContainer .dayName {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
#cineraIndex.mobile #cineraResults .dayContainer .markerList {
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.cinera.mobile
|
||||
{
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-grow: 0;
|
||||
-webkit-text-size-adjust: none;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraMenus {
|
||||
justify-content: center;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
position: relative;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraMenus,
|
||||
.cinera.mobile .player_container {
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraMenus .episode_name,
|
||||
.cinera.mobile .cineraMenus > .menu > .view,
|
||||
.cinera.mobile .cineraMenus > .menu > .views_container .view,
|
||||
.cinera.mobile .cineraHelp,
|
||||
#cineraIndex.mobile .cineraHelp,
|
||||
.cinera.mobile .markers_container > .episodeMarker div:nth-child(2),
|
||||
.cinera.mobile .markers_container > .episodeMarker div:nth-child(3),
|
||||
.cinera.mobile .markers_container > .markers .marker:not(.current) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraMenus .menu {
|
||||
position: static;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraMenus .menu .quotes_container,
|
||||
.cinera.mobile .cineraMenus .menu .references_container,
|
||||
.cinera.mobile .cineraMenus .menu .filter_container,
|
||||
.cinera.mobile .cineraMenus .menu .link_container,
|
||||
.cinera.mobile .cineraMenus .menu .credits_container {
|
||||
box-sizing: border-box;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container {
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
overflow-y: hidden;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker {
|
||||
width: 32px;
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .markers {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.first,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.prev,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .markers .marker,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.last,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.next {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.first,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.prev {
|
||||
border-right: 3px double;
|
||||
}
|
||||
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.last,
|
||||
.cinera.mobile .cineraPlayerContainer .markers_container > .episodeMarker.next {
|
||||
border-left: 3px double;
|
||||
}
|
||||
/* Mobile Style End */
|
||||
|
||||
/* CUSTOM PAGE STYLE */
|
||||
|
||||
/*
|
||||
|
@ -889,4 +1082,4 @@ Open menu: ▾ ▾
|
|||
Open link in new tab: ⤻ or &10559; or &8599; or ⭷
|
||||
Play from timecode: ⏵ (or, if ↓ ▸)
|
||||
Playable from timecode: ▹
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -516,7 +516,7 @@ typedef struct project
|
|||
asset *IconAsset;
|
||||
|
||||
string StreamUsername;
|
||||
string VODPlatform;
|
||||
string VODPlatform; // TODO(matt): Make this an enum
|
||||
|
||||
bool DenyBespokeTemplates;
|
||||
bool SingleBrowserTab;
|
||||
|
@ -2615,7 +2615,7 @@ string
|
|||
DeriveLineageWithoutOriginOfProject(config *C, scope_tree *Project)
|
||||
{
|
||||
string Result = {};
|
||||
memory_book StringList = {};
|
||||
memory_book StringList = InitBookOfPointers(MBT_STRING_PTR, 4);
|
||||
if(Project->Parent && Project->Parent->ID.Key == IDENT_PROJECT)
|
||||
{
|
||||
string **Writer = MakeSpaceInBook(&StringList);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -54,7 +54,8 @@ function Player(htmlContainer, refsCallback) {
|
|||
}.bind(this));
|
||||
|
||||
Player.initializeYoutube(this.onYoutubeReady.bind(this));
|
||||
this.updateSize();
|
||||
var PendingMobileStyleInitialisation = true;
|
||||
this.updateSize(PendingMobileStyleInitialisation);
|
||||
this.resume();
|
||||
}
|
||||
|
||||
|
@ -99,6 +100,11 @@ Player.prototype.setTime = function(time) {
|
|||
Player.prototype.jumpToNextMarker = function() {
|
||||
var targetMarkerIdx = Math.min((this.currentMarkerIdx === null ? 0 : this.currentMarkerIdx + 1), this.markers.length-1);
|
||||
var targetTime = this.markers[targetMarkerIdx].timestamp;
|
||||
while(targetMarkerIdx < this.markers.length && this.markers[targetMarkerIdx].el.classList.contains("skip"))
|
||||
{
|
||||
++targetMarkerIdx;
|
||||
targetTime = this.markers[targetMarkerIdx].timestamp;
|
||||
}
|
||||
this.setTime(targetTime);
|
||||
this.play();
|
||||
};
|
||||
|
@ -106,35 +112,310 @@ Player.prototype.jumpToNextMarker = function() {
|
|||
Player.prototype.jumpToPrevMarker = function() {
|
||||
var targetMarkerIdx = Math.max(0, (this.currentMarkerIdx === null ? 0 : this.currentMarkerIdx - 1));
|
||||
var targetTime = this.markers[targetMarkerIdx].timestamp;
|
||||
while(targetMarkerIdx >= 0 && this.markers[targetMarkerIdx].el.classList.contains("skip"))
|
||||
{
|
||||
--targetMarkerIdx;
|
||||
targetTime = this.markers[targetMarkerIdx].timestamp;
|
||||
}
|
||||
this.setTime(targetTime);
|
||||
this.play();
|
||||
};
|
||||
|
||||
function switchToMobileView(player)
|
||||
function
|
||||
GetHeightOfHideableElement(Element, UnhidingClass)
|
||||
{
|
||||
var Result = 0;
|
||||
if(Element.classList.contains(UnhidingClass))
|
||||
{
|
||||
Result = Element.offsetHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ZOffset = Element.style.zOffset;
|
||||
Element.style.zOffset = -1;
|
||||
Element.classList.add(UnhidingClass);
|
||||
|
||||
Result = Element.offsetHeight;
|
||||
|
||||
Element.classList.remove(UnhidingClass);
|
||||
Element.style.zOffset = ZOffset;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
GetWidthOfHideableElement(Element, UnhidingClass)
|
||||
{
|
||||
var Result = 0;
|
||||
if(Element.classList.contains(UnhidingClass))
|
||||
{
|
||||
Result = Element.offsetWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ZOffset = Element.style.zOffset;
|
||||
Element.style.zOffset = -1;
|
||||
Element.classList.add(UnhidingClass);
|
||||
|
||||
Result = Element.offsetWidth;
|
||||
|
||||
Element.classList.remove(UnhidingClass);
|
||||
Element.style.zOffset = ZOffset;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
ComputeVerticalOffsetForMenu(Menu, Toggler, VideoContainerDimY)
|
||||
{
|
||||
console.log("ComputeVerticalOffsetForMenu()");
|
||||
var Result = 0;
|
||||
var MenuHeight = GetHeightOfHideableElement(Menu, "visible");
|
||||
var TogglerHeight = Toggler.offsetHeight;
|
||||
|
||||
var TogglerOffset = Toggler.offsetTop;
|
||||
var Result = TogglerOffset + (TogglerHeight / 2) - (MenuHeight / 2);
|
||||
|
||||
console.log("Lower Point (0): " + (Result + MenuHeight));
|
||||
console.log("VideoContainerDimY (0): " + VideoContainerDimY);
|
||||
var LowerProtrusion = MenuHeight + Result - VideoContainerDimY;
|
||||
if(LowerProtrusion > 0)
|
||||
{
|
||||
Result -= LowerProtrusion;
|
||||
}
|
||||
console.log("Lower Point (1): " + (Result + MenuHeight));
|
||||
console.log("VideoContainerDimY (1): " + VideoContainerDimY);
|
||||
|
||||
if(Result < 0)
|
||||
{
|
||||
Result = 0;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function sizeAndPositionMenuContainer(TitleBar, SizerElement, Menu)
|
||||
{
|
||||
if(Menu)
|
||||
{
|
||||
var Toggler = Menu.parentElement;
|
||||
|
||||
var TitleBarDimX = TitleBar.offsetWidth;
|
||||
var TitleBarDimY = TitleBar.offsetHeight;
|
||||
var SizerElementDimX = SizerElement.offsetWidth;
|
||||
var SizerElementDimY = SizerElement.offsetHeight;
|
||||
|
||||
var ContainerDimX = SizerElementDimX;
|
||||
var ContainerDimY = SizerElementDimY;
|
||||
|
||||
switch(cineraProps.O)
|
||||
{
|
||||
case orientations.PORTRAIT:
|
||||
{
|
||||
Menu.style.borderTopWidth = 0;
|
||||
Menu.style.borderTopStyle = "none";
|
||||
Menu.style.borderRightWidth = "1px";
|
||||
Menu.style.borderRightStyle = "solid";
|
||||
Menu.style.borderLeftWidth = "1px";
|
||||
Menu.style.borderLeftStyle = "solid";
|
||||
|
||||
Menu.style.maxWidth = ContainerDimX + "px";
|
||||
ContainerDimY -= TitleBarDimY;
|
||||
Menu.style.maxHeight = ContainerDimY + "px";
|
||||
|
||||
Menu.style.top = TitleBarDimY + "px";
|
||||
Menu.style.left = 0 + "px";
|
||||
} break;
|
||||
case orientations.LANDSCAPE_LEFT:
|
||||
{
|
||||
Menu.style.borderTopWidth = "1px";
|
||||
Menu.style.borderTopStyle = "solid";
|
||||
Menu.style.borderRightWidth = "1px";
|
||||
Menu.style.borderRightStyle = "solid";
|
||||
Menu.style.borderLeftWidth = 0;
|
||||
Menu.style.borderLeftStyle = "none";
|
||||
|
||||
ContainerDimX -= TitleBarDimX;
|
||||
Menu.style.maxWidth = ContainerDimX + "px";
|
||||
Menu.style.maxHeight = ContainerDimY + "px";
|
||||
|
||||
var MenuVerticalOffset = ComputeVerticalOffsetForMenu(Menu, Toggler, SizerElementDimY);
|
||||
|
||||
Menu.style.top = MenuVerticalOffset + "px";
|
||||
Menu.style.left = TitleBarDimX + "px";
|
||||
} break;
|
||||
case orientations.LANDSCAPE_RIGHT:
|
||||
{
|
||||
Menu.style.borderTopWidth = "1px";
|
||||
Menu.style.borderTopStyle = "solid";
|
||||
Menu.style.borderRightWidth = 0;
|
||||
Menu.style.borderRightStyle = "none";
|
||||
Menu.style.borderLeftWidth = "1px";
|
||||
Menu.style.borderLeftStyle = "solid";
|
||||
|
||||
ContainerDimX -= TitleBarDimX;
|
||||
Menu.style.maxWidth = ContainerDimX + "px";
|
||||
Menu.style.maxHeight = ContainerDimY + "px";
|
||||
|
||||
var MenuVerticalOffset = ComputeVerticalOffsetForMenu(Menu, Toggler, SizerElementDimY);
|
||||
|
||||
Menu.style.top = MenuVerticalOffset + "px";
|
||||
var MenuWidth = GetWidthOfHideableElement(Menu, "visible");
|
||||
Menu.style.left = -MenuWidth + "px";
|
||||
} break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function
|
||||
ComputeTallest(Elements, UnhidingClass)
|
||||
{
|
||||
var Result = null;
|
||||
for(var i = 0; i < Elements.length; ++i)
|
||||
{
|
||||
var This = Elements[i];
|
||||
var Height = UnhidingClass ? GetHeightOfHideableElement(This, UnhidingClass) : This.offsetHeight;
|
||||
if(Height > Result)
|
||||
{
|
||||
Result = Height;
|
||||
}
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
ComputeAndSetTallest(Selector, Elements, UnhidingClass)
|
||||
{
|
||||
Selector.style.height = "unset";
|
||||
Selector.style.height = ComputeTallest(Elements, UnhidingClass) + "px";
|
||||
}
|
||||
|
||||
function ApplyMobileStyle(player)
|
||||
{
|
||||
var MaxWidth = MaxWidthOfElement(cinera);
|
||||
var MaxHeight = MaxHeightOfElement(cinera);
|
||||
|
||||
var IndicesBar = playerContainer.querySelector(".markers_container");
|
||||
var Markers = IndicesBar.querySelector(".markers");
|
||||
var CineraContentWidth = MaxWidth;
|
||||
|
||||
var EpisodeMarkers = IndicesBar.querySelectorAll(".episodeMarker");
|
||||
for(var i = 0; i < EpisodeMarkers.length; ++i)
|
||||
{
|
||||
CineraContentWidth -= EpisodeMarkers[i].offsetWidth;
|
||||
}
|
||||
|
||||
switch(cineraProps.O)
|
||||
{
|
||||
case orientations.PORTRAIT:
|
||||
{
|
||||
cinera.style.flexDirection = "column";
|
||||
titleBar.style.flexDirection = "row";
|
||||
} break;
|
||||
case orientations.LANDSCAPE_LEFT:
|
||||
{
|
||||
cinera.style.flexDirection = "row";
|
||||
titleBar.style.flexDirection = "column-reverse";
|
||||
CineraContentWidth -= titleBar.offsetWidth;
|
||||
} break;
|
||||
case orientations.LANDSCAPE_RIGHT:
|
||||
{
|
||||
cinera.style.flexDirection = "row-reverse";
|
||||
titleBar.style.flexDirection = "column";
|
||||
CineraContentWidth -= titleBar.offsetWidth;
|
||||
} break;
|
||||
}
|
||||
|
||||
if(MobileCineraContentRule !== undefined)
|
||||
{
|
||||
MobileCineraContentRule.style.width = CineraContentWidth + "px";
|
||||
var MarkerList = Markers.querySelectorAll(".marker");
|
||||
ComputeAndSetTallest(MobileCineraContentRule, MarkerList, "current");
|
||||
}
|
||||
|
||||
var VideoMaxDimX = null;
|
||||
var VideoMaxDimY = null;
|
||||
|
||||
switch(cineraProps.O)
|
||||
{
|
||||
case orientations.PORTRAIT:
|
||||
{
|
||||
VideoMaxDimX = MaxWidth;
|
||||
VideoMaxDimY = MaxHeight - IndicesBar.offsetHeight - titleBar.offsetHeight;
|
||||
} break;
|
||||
case orientations.LANDSCAPE_LEFT:
|
||||
case orientations.LANDSCAPE_RIGHT:
|
||||
{
|
||||
VideoMaxDimX = MaxWidth - titleBar.offsetWidth;
|
||||
VideoMaxDimY = MaxHeight - IndicesBar.offsetHeight;
|
||||
} break;
|
||||
}
|
||||
|
||||
var VideoDimYFromMaxX = VideoMaxDimX * 9 / 16;
|
||||
var VideoDimXFromMaxY = VideoMaxDimY * 16 / 9;
|
||||
|
||||
var VideoDimX = 0;
|
||||
var VideoDimY = 0;
|
||||
if(VideoDimXFromMaxY > VideoMaxDimX)
|
||||
{
|
||||
VideoDimX = Math.floor(VideoMaxDimX);
|
||||
VideoDimY = Math.floor(VideoDimYFromMaxX);
|
||||
}
|
||||
else if(VideoDimYFromMaxX > VideoMaxDimY)
|
||||
{
|
||||
VideoDimY = Math.floor(VideoMaxDimY);
|
||||
VideoDimX = Math.floor(VideoDimXFromMaxY);
|
||||
}
|
||||
else
|
||||
{
|
||||
VideoDimX = Math.floor(VideoMaxDimX);
|
||||
VideoDimY = Math.floor(VideoDimYFromMaxX);
|
||||
}
|
||||
|
||||
var VideoContainer = cinera.querySelector(".video_container");
|
||||
|
||||
VideoContainer.style.width = VideoDimX + "px";
|
||||
VideoContainer.style.height = VideoDimY + "px";
|
||||
|
||||
sizeAndPositionMenuContainer(titleBar, cinera, quotesMenu);
|
||||
sizeAndPositionMenuContainer(titleBar, cinera, referencesMenu);
|
||||
sizeAndPositionMenuContainer(titleBar, cinera, filterMenu);
|
||||
sizeAndPositionMenuContainer(titleBar, cinera, linkMenu);
|
||||
sizeAndPositionMenuContainer(titleBar, cinera, creditsMenu);
|
||||
}
|
||||
|
||||
function
|
||||
IconifyMenuTogglers()
|
||||
{
|
||||
var menuContainerOffset = getElementYOffsetFromPage(titleBar) + parseInt(window.getComputedStyle(titleBar).height);
|
||||
if(quotesMenu)
|
||||
{
|
||||
quotesMenu.previousElementSibling.textContent = '\u{1F5E9}';
|
||||
quotesMenu.style.top = menuContainerOffset + "px";
|
||||
}
|
||||
|
||||
if(referencesMenu)
|
||||
{
|
||||
referencesMenu.previousElementSibling.textContent = '\u{1F4D6}';
|
||||
referencesMenu.style.top = menuContainerOffset + "px";
|
||||
}
|
||||
|
||||
if(filterMenu) { filterMenu.style.top = menuContainerOffset + "px"; }
|
||||
if(linkMenu) { linkMenu.style.top = menuContainerOffset + "px"; }
|
||||
|
||||
if(creditsMenu) {
|
||||
if(creditsMenu)
|
||||
{
|
||||
creditsMenu.previousElementSibling.textContent = '\u{1F46A}';
|
||||
creditsMenu.style.top = menuContainerOffset + "px";
|
||||
}
|
||||
|
||||
if(viewsMenu)
|
||||
{
|
||||
viewsMenu.remove();
|
||||
viewsMenu = null;
|
||||
}
|
||||
}
|
||||
|
||||
function
|
||||
InitMobileControls()
|
||||
{
|
||||
var rightmost = {};
|
||||
var markersContainer = player.markersContainer;
|
||||
var markersContainer = cinera.querySelector(".markers_container");
|
||||
markersContainer.style.height = "auto";
|
||||
var episodeMarkerFirst = markersContainer.querySelector(".episodeMarker.first");
|
||||
var episodeMarkerPrev = markersContainer.querySelector(".episodeMarker.prev");
|
||||
var episodeMarkerNext = markersContainer.querySelector(".episodeMarker.next");
|
||||
var episodeMarkerLast = markersContainer.querySelector(".episodeMarker.last");
|
||||
|
@ -143,94 +424,70 @@ function switchToMobileView(player)
|
|||
if(episodeMarkerNext) { episodeMarkerNext.firstChild.textContent = '\u{23ED}'; rightmost = episodeMarkerNext; }
|
||||
else if (episodeMarkerLast) { rightmost = episodeMarkerLast; }
|
||||
|
||||
var controlPrevTimestamp = document.createElement("a");
|
||||
controlPrevTimestamp.classList.add("episodeMarker");
|
||||
controlPrevTimestamp.classList.add("prevTimestamp");
|
||||
var controlPrevTimestampContent = document.createElement("div");
|
||||
controlPrevTimestampContent.appendChild(document.createTextNode('\u{25C0}'));
|
||||
controlPrevTimestamp.appendChild(controlPrevTimestampContent);
|
||||
|
||||
var markers = markersContainer.querySelector(".markers");
|
||||
markersContainer.insertBefore(controlPrevTimestamp, markers);
|
||||
|
||||
var controlPrevAnnotation = document.createElement("a");
|
||||
controlPrevAnnotation.classList.add("episodeMarker");
|
||||
controlPrevAnnotation.classList.add("prevAnnotation");
|
||||
controlPrevAnnotation.addEventListener("click", function(ev) {
|
||||
player.jumpToPrevMarker();
|
||||
});
|
||||
var controlPrevAnnotationContent = document.createElement("div");
|
||||
controlPrevAnnotationContent.appendChild(document.createTextNode('\u{23F4}'));
|
||||
controlPrevAnnotation.appendChild(controlPrevAnnotationContent);
|
||||
|
||||
markersContainer.insertBefore(controlPrevAnnotation, markers);
|
||||
|
||||
var controlNextAnnotation = document.createElement("a");
|
||||
controlNextAnnotation.classList.add("episodeMarker");
|
||||
controlNextAnnotation.classList.add("nextAnnotation");
|
||||
controlNextAnnotation.addEventListener("click", function(ev) {
|
||||
player.jumpToNextMarker();
|
||||
});
|
||||
var controlNextAnnotationContent = document.createElement("div");
|
||||
controlNextAnnotationContent.appendChild(document.createTextNode('\u{23F5}'));
|
||||
controlNextAnnotation.appendChild(controlNextAnnotationContent);
|
||||
var controlNextTimestamp = document.createElement("a");
|
||||
controlNextTimestamp.classList.add("episodeMarker");
|
||||
controlNextTimestamp.classList.add("nextTimestamp");
|
||||
var controlNextTimestampContent = document.createElement("div");
|
||||
controlNextTimestampContent.appendChild(document.createTextNode('\u{25B6}'));
|
||||
controlNextTimestamp.appendChild(controlNextTimestampContent);
|
||||
|
||||
if(rightmost)
|
||||
{
|
||||
markersContainer.insertBefore(controlNextAnnotation, rightmost);
|
||||
markersContainer.insertBefore(controlNextTimestamp, rightmost);
|
||||
}
|
||||
else
|
||||
{
|
||||
markersContainer.appendChild(controlNextAnnotation);
|
||||
markersContainer.appendChild(controlNextTimestamp);
|
||||
}
|
||||
|
||||
cineraProps.D = devices.MOBILE;
|
||||
}
|
||||
|
||||
function switchToDesktopView(player)
|
||||
function InitMobileStyle()
|
||||
{
|
||||
if(quotesMenu)
|
||||
{
|
||||
quotesMenu.previousElementSibling.textContent = originalTextContent.TitleQuotes;
|
||||
quotesMenu.style.top = "100%";
|
||||
}
|
||||
if(referencesMenu)
|
||||
{
|
||||
referencesMenu.previousElementSibling.textContent = originalTextContent.TitleReferences;
|
||||
referencesMenu.style.top = "100%";
|
||||
}
|
||||
if(filterMenu) { filterMenu.style.top = "100%"; }
|
||||
if(linkMenu) { linkMenu.style.top = "100%"; }
|
||||
if(creditsMenu)
|
||||
{
|
||||
creditsMenu.previousElementSibling.textContent = originalTextContent.TitleCredits;
|
||||
creditsMenu.style.top = "100%";
|
||||
}
|
||||
cinera.classList.add("mobile");
|
||||
IconifyMenuTogglers();
|
||||
InitMobileControls();
|
||||
ApplyMobileStyle();
|
||||
}
|
||||
|
||||
function
|
||||
ConnectMobileControls(player)
|
||||
{
|
||||
var markersContainer = player.markersContainer;
|
||||
|
||||
var episodeMarkerPrev = markersContainer.querySelector(".episodeMarker.prev");
|
||||
if(episodeMarkerPrev) { episodeMarkerPrev.firstChild.textContent = originalTextContent.EpisodePrev; }
|
||||
var episodeMarkerNext = markersContainer.querySelector(".episodeMarker.next");
|
||||
if(episodeMarkerNext) { episodeMarkerNext.firstChild.textContent = originalTextContent.EpisodeNext; }
|
||||
|
||||
var prevAnnotation = markersContainer.querySelector(".episodeMarker.prevAnnotation");
|
||||
markersContainer.removeChild(prevAnnotation);
|
||||
var nextAnnotation = markersContainer.querySelector(".episodeMarker.nextAnnotation");
|
||||
markersContainer.removeChild(nextAnnotation);
|
||||
cineraProps.D = devices.DESKTOP;
|
||||
var ControlPrevTimestamp = markersContainer.querySelector(".episodeMarker.prevTimestamp");
|
||||
ControlPrevTimestamp.addEventListener("click", function(ev) {
|
||||
player.jumpToPrevMarker();
|
||||
});
|
||||
var ControlNextTimestamp = markersContainer.querySelector(".episodeMarker.nextTimestamp");
|
||||
ControlNextTimestamp.addEventListener("click", function(ev) {
|
||||
player.jumpToNextMarker();
|
||||
});
|
||||
}
|
||||
|
||||
// Call this after changing the size of the video container in order to update the youtube player.
|
||||
Player.prototype.updateSize = function() {
|
||||
var width = this.videoContainer.offsetWidth;
|
||||
var height = width / 16 * 9;
|
||||
if(window.innerHeight > 512 && window.innerWidth > 720)
|
||||
var width = 0;
|
||||
var height = 0;
|
||||
if(cineraProps.D === devices.DESKTOP)
|
||||
{
|
||||
if(cineraProps.D == devices.MOBILE)
|
||||
{
|
||||
switchToDesktopView(this);
|
||||
}
|
||||
this.markersContainer.style.height = height + "px"; // NOTE(matt): This was the original line here
|
||||
width = this.videoContainer.offsetWidth;
|
||||
height = width / 16 * 9; // TODO(matt): Get the aspect ratio from the video itself?
|
||||
this.markersContainer.style.height = height + "px";
|
||||
}
|
||||
else
|
||||
{
|
||||
if(cineraProps.D == devices.DESKTOP)
|
||||
{
|
||||
switchToMobileView(this);
|
||||
}
|
||||
ApplyMobileStyle();
|
||||
width = this.videoContainer.offsetWidth;
|
||||
height = this.videoContainer.offsetHeight;
|
||||
}
|
||||
|
||||
if (this.youtubePlayerReady) {
|
||||
|
@ -288,25 +545,10 @@ Player.prototype.onMarkerClick = function(marker, ev) {
|
|||
this.play();
|
||||
};
|
||||
|
||||
function getElementXOffsetFromPage(el) {
|
||||
var left = 0;
|
||||
do {
|
||||
left += el.offsetLeft;
|
||||
} while (el = el.offsetParent);
|
||||
return left;
|
||||
}
|
||||
|
||||
function getElementYOffsetFromPage(el) {
|
||||
var top = 0;
|
||||
do {
|
||||
top += el.offsetTop;
|
||||
} while (el = el.offsetParent);
|
||||
return top;
|
||||
}
|
||||
|
||||
Player.prototype.onMarkerMouseMove = function(marker, ev) {
|
||||
if (this.currentMarker == marker) {
|
||||
marker.hoverx = (ev.pageX - getElementXOffsetFromPage(marker.el)) / marker.el.offsetWidth;
|
||||
var CineraContent = this.currentMarker.el.querySelector(".cineraContent");
|
||||
marker.hoverx = (ev.pageX - getElementXOffsetFromPage(CineraContent)) / CineraContent.offsetWidth;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -329,7 +571,8 @@ Player.prototype.updateProgress = function() {
|
|||
}
|
||||
|
||||
if (this.currentMarker) {
|
||||
var totalWidth = this.currentMarker.el.offsetWidth;
|
||||
var CineraContent = this.currentMarker.el.querySelector(".cineraContent");
|
||||
var totalWidth = CineraContent.offsetWidth;
|
||||
var progress = (this.currentTime - this.currentMarker.timestamp) / (this.currentMarker.endTime - this.currentMarker.timestamp);
|
||||
if (this.currentMarker.hoverx === null) {
|
||||
var pixelWidth = progress * totalWidth;
|
||||
|
@ -364,9 +607,6 @@ Player.prototype.updateProgress = function() {
|
|||
this.currentMarker.el.classList.add("current");
|
||||
this.scrollTo = this.currentMarker.el.offsetTop + this.currentMarker.el.offsetHeight/2.0;
|
||||
this.scrollPosition = this.markersContainer.scrollTop;
|
||||
}
|
||||
|
||||
if (this.currentMarker) {
|
||||
this.refsCallback(this.currentMarker.ref, this.currentMarker.el, this);
|
||||
} else if (prevMarker && prevMarker.ref) {
|
||||
this.refsCallback(null);
|
||||
|
@ -445,6 +685,7 @@ Player.prototype.onYoutubeReady = function() {
|
|||
videoId: this.videoContainer.getAttribute("data-videoId"),
|
||||
width: this.videoContainer.offsetWidth,
|
||||
height: this.videoContainer.offsetWidth / 16 * 9,
|
||||
playerVars: { 'playsinline': 1 },
|
||||
//playerVars: { disablekb: 1 },
|
||||
events: {
|
||||
"onReady": this.onYoutubePlayerReady.bind(this),
|
||||
|
@ -636,13 +877,13 @@ function enterFullScreen_()
|
|||
{
|
||||
if(!document.mozFullScreen && !document.webkitFullScreen)
|
||||
{
|
||||
if(cinera.mozRequestFullScreen)
|
||||
if(document.mozRequestFullScreen)
|
||||
{
|
||||
cinera.mozRequestFullScreen();
|
||||
document.mozRequestFullScreen();
|
||||
}
|
||||
else
|
||||
{
|
||||
cinera.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
document.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -673,6 +914,11 @@ function toggleTheatreMode() {
|
|||
cineraProps.H = cinera.style.height;
|
||||
cineraProps.mH = cinera.style.maxHeight;
|
||||
cineraProps.P = cinera.style.position;
|
||||
cineraProps.Display = cinera.style.display;
|
||||
cineraProps.FlexDirection = cinera.style.flexDirection;
|
||||
cineraProps.JustifyContent = cinera.style.justifyContent;
|
||||
cineraProps.ScrollX = window.scrollX;
|
||||
cineraProps.ScrollY = window.scrollY;
|
||||
|
||||
cinera.style.backgroundColor = "#000";
|
||||
cinera.style.zIndex = 64;
|
||||
|
@ -683,6 +929,9 @@ function toggleTheatreMode() {
|
|||
cinera.style.height = "100%";
|
||||
cinera.style.maxHeight = "100%";
|
||||
cinera.style.position = "fixed";
|
||||
cinera.style.display = "flex";
|
||||
cinera.style.flexDirection = "column";
|
||||
cinera.style.justifyContent = "center";
|
||||
|
||||
viewItems[0].setAttribute("data-id", "regular");
|
||||
viewItems[0].setAttribute("title", "Regular mode");
|
||||
|
@ -703,6 +952,15 @@ function toggleTheatreMode() {
|
|||
cinera.style.height = cineraProps.H;
|
||||
cinera.style.maxHeight = cineraProps.mH;
|
||||
cinera.style.position = cineraProps.P;
|
||||
cinera.style.display = cineraProps.Display;
|
||||
cinera.style.flexDirection = cineraProps.FlexDirection;
|
||||
cinera.style.justifyContent = cineraProps.JustifyContent;
|
||||
window.scroll(
|
||||
{
|
||||
top: cineraProps.ScrollY,
|
||||
left: cineraProps.ScrollX
|
||||
}
|
||||
);
|
||||
|
||||
viewItems[0].setAttribute("data-id", "theatre");
|
||||
viewItems[0].setAttribute("title", "Theatre mode");
|
||||
|
@ -859,10 +1117,12 @@ function handleKey(key) {
|
|||
if(focusedElement.previousElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedQuote = focusedElement.previousElementSibling;
|
||||
focusedElement = lastFocusedQuote;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("references_container"))
|
||||
|
@ -870,15 +1130,19 @@ function handleKey(key) {
|
|||
if(focusedElement.previousElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
|
||||
lastFocusedReference = focusedElement.previousElementSibling;
|
||||
focusedElement = lastFocusedReference;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
|
||||
lastFocusedIdentifier = focusedElement.querySelector(".ref_indices").firstElementChild;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.parentNode.classList.contains("filters"))
|
||||
|
@ -887,10 +1151,12 @@ function handleKey(key) {
|
|||
focusedElement.previousElementSibling.classList.contains("filter_content"))
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedCategory = focusedElement.previousElementSibling;
|
||||
focusedElement = lastFocusedCategory;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("credit"))
|
||||
|
@ -898,6 +1164,7 @@ function handleKey(key) {
|
|||
if(focusedElement.parentNode.previousElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
if(focusedElement.parentNode.previousElementSibling.querySelector(".support") &&
|
||||
focusedElement.classList.contains("support"))
|
||||
{
|
||||
|
@ -905,13 +1172,14 @@ function handleKey(key) {
|
|||
lastFocusedCreditItem = focusedElement.parentNode.previousElementSibling.querySelector(".support");
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
setSpriteLightness(focusedElement.firstChild);
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastFocusedCreditItem = focusedElement.parentNode.previousElementSibling.querySelector(".person");
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -926,10 +1194,12 @@ function handleKey(key) {
|
|||
if(focusedElement.nextElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedQuote = focusedElement.nextElementSibling;
|
||||
focusedElement = lastFocusedQuote;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("references_container"))
|
||||
|
@ -937,15 +1207,19 @@ function handleKey(key) {
|
|||
if(focusedElement.nextElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
|
||||
lastFocusedReference = focusedElement.nextElementSibling;
|
||||
focusedElement = lastFocusedReference;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
|
||||
lastFocusedIdentifier = focusedElement.querySelector(".ref_indices").firstElementChild;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.parentNode.classList.contains("filters"))
|
||||
|
@ -954,10 +1228,12 @@ function handleKey(key) {
|
|||
focusedElement.nextElementSibling.classList.contains("filter_content"))
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedCategory = focusedElement.nextElementSibling;
|
||||
focusedElement = lastFocusedCategory;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("credit"))
|
||||
|
@ -965,6 +1241,7 @@ function handleKey(key) {
|
|||
if(focusedElement.parentNode.nextElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
if(focusedElement.parentNode.nextElementSibling.querySelector(".support") &&
|
||||
focusedElement.classList.contains("support"))
|
||||
{
|
||||
|
@ -972,13 +1249,14 @@ function handleKey(key) {
|
|||
lastFocusedCreditItem = focusedElement.parentNode.nextElementSibling.querySelector(".support");
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
setSpriteLightness(focusedElement.firstChild);
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
lastFocusedCreditItem = focusedElement.parentNode.nextElementSibling.querySelector(".person");
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -993,16 +1271,20 @@ function handleKey(key) {
|
|||
if(focusedIdentifier.previousElementSibling)
|
||||
{
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
lastFocusedIdentifier = focusedIdentifier.previousElementSibling;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
else if(focusedIdentifier.parentNode.previousElementSibling.classList.contains("ref_indices"))
|
||||
{
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
lastFocusedIdentifier = focusedIdentifier.parentNode.previousElementSibling.lastElementChild;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.classList.contains("filter_content"))
|
||||
|
@ -1011,6 +1293,7 @@ function handleKey(key) {
|
|||
focusedElement.parentNode.previousElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
lastFocusedMedium = focusedElement;
|
||||
|
||||
if(!lastFocusedTopic)
|
||||
|
@ -1020,6 +1303,7 @@ function handleKey(key) {
|
|||
lastFocusedCategory = lastFocusedTopic;
|
||||
focusedElement = lastFocusedCategory;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("credit"))
|
||||
|
@ -1027,14 +1311,14 @@ function handleKey(key) {
|
|||
if(focusedElement.classList.contains("support"))
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
console.log(focusedElement);
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedCreditItem = focusedElement.previousElementSibling;
|
||||
if(focusedElement.firstChild.classList.contains("cineraSprite"))
|
||||
{
|
||||
setSpriteLightness(focusedElement.firstChild);
|
||||
}
|
||||
setSpriteLightness(focusedElement.firstChild);
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1048,17 +1332,21 @@ function handleKey(key) {
|
|||
if(focusedIdentifier.nextElementSibling)
|
||||
{
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
|
||||
lastFocusedIdentifier = focusedIdentifier.nextElementSibling;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
else if(focusedIdentifier.parentNode.nextElementSibling)
|
||||
{
|
||||
focusedIdentifier.classList.remove("focused");
|
||||
unfocusSprite(focusedIdentifier);
|
||||
lastFocusedIdentifier = focusedIdentifier.parentNode.nextElementSibling.firstElementChild;
|
||||
focusedIdentifier = lastFocusedIdentifier;
|
||||
focusedIdentifier.classList.add("focused");
|
||||
focusSprite(focusedIdentifier);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.classList.contains("filter_content"))
|
||||
|
@ -1067,6 +1355,7 @@ function handleKey(key) {
|
|||
focusedElement.parentNode.nextElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
lastFocusedTopic = focusedElement;
|
||||
|
||||
if(!lastFocusedMedium)
|
||||
|
@ -1076,6 +1365,7 @@ function handleKey(key) {
|
|||
lastFocusedCategory = lastFocusedMedium;
|
||||
focusedElement = lastFocusedCategory;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
else if(focusedElement.parentNode.classList.contains("credit"))
|
||||
|
@ -1084,14 +1374,12 @@ function handleKey(key) {
|
|||
focusedElement.nextElementSibling)
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
|
||||
lastFocusedCreditItem = focusedElement.nextElementSibling;
|
||||
focusedElement = lastFocusedCreditItem;
|
||||
focusedElement.classList.add("focused");
|
||||
if(focusedElement.firstChild.classList.contains("cineraSprite"))
|
||||
{
|
||||
setSpriteLightness(focusedElement.firstChild);
|
||||
}
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1105,6 +1393,7 @@ function handleKey(key) {
|
|||
focusedElement.nextElementSibling.classList.contains("filter_content"))
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
if(focusedElement.parentNode.classList.contains("filter_topics"))
|
||||
{
|
||||
lastFocusedTopic = focusedElement.nextElementSibling;
|
||||
|
@ -1118,6 +1407,7 @@ function handleKey(key) {
|
|||
lastFocusedElement = lastFocusedCategory;
|
||||
focusedElement = lastFocusedElement;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -1130,6 +1420,7 @@ function handleKey(key) {
|
|||
focusedElement.previousElementSibling.classList.contains("filter_content"))
|
||||
{
|
||||
focusedElement.classList.remove("focused");
|
||||
unfocusSprite(focusedElement);
|
||||
if(focusedElement.parentNode.classList.contains("filter_topics"))
|
||||
{
|
||||
lastFocusedTopic = focusedElement.previousElementSibling;
|
||||
|
@ -1143,6 +1434,7 @@ function handleKey(key) {
|
|||
lastFocusedElement = lastFocusedCategory;
|
||||
focusedElement = lastFocusedElement;
|
||||
focusedElement.classList.add("focused");
|
||||
focusSprite(focusedElement);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
@ -1163,7 +1455,10 @@ function handleKey(key) {
|
|||
} break;
|
||||
|
||||
case "?": {
|
||||
helpDocumentation.classList.toggle("visible");
|
||||
if(helpDocumentation)
|
||||
{
|
||||
helpDocumentation.classList.toggle("visible");
|
||||
}
|
||||
} break;
|
||||
|
||||
case 'N':
|
||||
|
@ -1319,7 +1614,7 @@ function filterItemToggle(filterItem) {
|
|||
filterItem.querySelector(".icon").style.backgroundColor = getComputedStyle(filterItem.querySelector(".icon")).getPropertyValue("border-color");
|
||||
}
|
||||
setDotLightness(filterItem.querySelector(".icon"));
|
||||
var testMarkers = document.querySelectorAll(".marker.off_" + selectedCategory);
|
||||
var testMarkers = cinera.querySelectorAll(".marker.off_" + selectedCategory);
|
||||
for(var j = 0; j < testMarkers.length; ++j)
|
||||
{
|
||||
if(filterState[selectedCategory].type == "topic")
|
||||
|
@ -1461,35 +1756,36 @@ function onRefChanged(ref, element, player) {
|
|||
{
|
||||
player.jumpToNextMarker();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (var MenuIndex = 0; MenuIndex < sourceMenus.length; ++MenuIndex)
|
||||
else
|
||||
{
|
||||
var SetMenu = 0;
|
||||
if (ref !== undefined && ref !== null) {
|
||||
var refElements = sourceMenus[MenuIndex].querySelectorAll(".refs .ref");
|
||||
var refs = ref.split(",");
|
||||
for (var MenuIndex = 0; MenuIndex < sourceMenus.length; ++MenuIndex)
|
||||
{
|
||||
var SetMenu = 0;
|
||||
if (ref !== undefined && ref !== null) {
|
||||
var refElements = sourceMenus[MenuIndex].querySelectorAll(".refs .ref");
|
||||
var refs = ref.split(",");
|
||||
|
||||
for (var i = 0; i < refElements.length; ++i) {
|
||||
if (refs.includes(refElements[i].getAttribute("data-id"))) {
|
||||
refElements[i].classList.add("current");
|
||||
SetMenu = 1;
|
||||
} else {
|
||||
refElements[i].classList.remove("current");
|
||||
for (var i = 0; i < refElements.length; ++i) {
|
||||
if (refs.includes(refElements[i].getAttribute("data-id"))) {
|
||||
refElements[i].classList.add("current");
|
||||
SetMenu = 1;
|
||||
} else {
|
||||
refElements[i].classList.remove("current");
|
||||
}
|
||||
}
|
||||
}
|
||||
if(SetMenu) {
|
||||
sourceMenus[MenuIndex].classList.add("current");
|
||||
if(SetMenu) {
|
||||
sourceMenus[MenuIndex].classList.add("current");
|
||||
} else {
|
||||
sourceMenus[MenuIndex].classList.remove("current");
|
||||
}
|
||||
|
||||
} else {
|
||||
sourceMenus[MenuIndex].classList.remove("current");
|
||||
}
|
||||
|
||||
} else {
|
||||
sourceMenus[MenuIndex].classList.remove("current");
|
||||
var refs = sourceMenus[MenuIndex].querySelectorAll(".refs .ref");
|
||||
for (var i = 0; i < refs.length; ++i) {
|
||||
refs[i].classList.remove("current");
|
||||
var refs = sourceMenus[MenuIndex].querySelectorAll(".refs .ref");
|
||||
for (var i = 0; i < refs.length; ++i) {
|
||||
refs[i].classList.remove("current");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1574,10 +1870,11 @@ function mouseSkipToTimecode(player, time, ev)
|
|||
return false;
|
||||
}
|
||||
|
||||
function handleMouseOverMenu(menu, eventType)
|
||||
function handleMenuTogglerInteraction(menu, eventType)
|
||||
{
|
||||
if(!(menu.classList.contains("visible")) && eventType == "mouseenter" ||
|
||||
menu.classList.contains("visible") && eventType == "mouseleave")
|
||||
menu.classList.contains("visible") && eventType == "mouseleave" ||
|
||||
(eventType == "click" && !menu.classList.contains("cineraHelp")))
|
||||
{
|
||||
if(menu.classList.contains("quotes"))
|
||||
{
|
||||
|
@ -1600,10 +1897,6 @@ function handleMouseOverMenu(menu, eventType)
|
|||
toggleMenuVisibility(creditsMenu);
|
||||
}
|
||||
}
|
||||
if(eventType == "click" && menu.classList.contains("help"))
|
||||
{
|
||||
helpDocumentation.classList.toggle("visible");
|
||||
}
|
||||
}
|
||||
|
||||
function RGBtoHSL(colour)
|
||||
|
@ -1648,7 +1941,6 @@ function getBackgroundBrightness(element) {
|
|||
var result = Math.sqrt(rgb[0] * rgb[0] * .241 +
|
||||
rgb[1] * rgb[1] * .691 +
|
||||
rgb[2] * rgb[2] * .068);
|
||||
console.log(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,24 @@
|
|||
var orientations = {
|
||||
PORTRAIT: 0,
|
||||
LANDSCAPE_LEFT: 90,
|
||||
LANDSCAPE_RIGHT: -90,
|
||||
};
|
||||
|
||||
var DebugConsoleMessageCount = 0;
|
||||
function Say(Message)
|
||||
{
|
||||
var DebugConsole = document.getElementById("debug-console");
|
||||
if(DebugConsole)
|
||||
{
|
||||
DebugConsole.textContent += DebugConsoleMessageCount++ + ": " + Message + "\n";
|
||||
DebugConsole.scrollTo(
|
||||
{
|
||||
top: DebugConsole.scrollHeight,
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getBackgroundBrightness(element) {
|
||||
var colour = getComputedStyle(element).getPropertyValue("background-color");
|
||||
var depth = 0;
|
||||
|
@ -110,3 +131,233 @@ function unfocusSprite(Element)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
function IsMobile() {
|
||||
// NOTE(matt): From https://medium.com/simplejs/detect-the-users-device-type-with-a-simple-javascript-check-4fc656b735e1
|
||||
var Identifier = navigator.userAgent||navigator.vendor||window.opera;
|
||||
var Result = (/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino/i.test(Identifier)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(Identifier.substr(0,4)));
|
||||
return Result;
|
||||
};
|
||||
|
||||
function GetRule(SelectorText)
|
||||
{
|
||||
// NOTE(matt): Modifying CSS style
|
||||
// from https://stackoverflow.com/a/566445
|
||||
// https://usefulangle.com/post/39/adding-css-to-stylesheet-with-javascript
|
||||
var Result = undefined;
|
||||
|
||||
var StyleSheets = document.styleSheets;
|
||||
var cssRuleCode = document.all ? 'rules' : 'cssRules'; // account for IE and FF
|
||||
for(var StyleSheetIndex = StyleSheets.length - 1; StyleSheetIndex >= 0; --StyleSheetIndex)
|
||||
{
|
||||
var ThisSheet = StyleSheets[StyleSheetIndex];
|
||||
var Rules = ThisSheet[cssRuleCode];
|
||||
for(var RuleIndex = Rules.length - 1; RuleIndex >= 0; --RuleIndex)
|
||||
{
|
||||
var ThisRule = Rules[RuleIndex];
|
||||
if(SelectorText === ThisRule.selectorText)
|
||||
{
|
||||
Result = ThisRule;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(Result !== undefined) { break; }
|
||||
}
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
GetRulesOfStyleSheetIndex(Index)
|
||||
{
|
||||
var Result = undefined;
|
||||
var StyleSheets = document.styleSheets;
|
||||
var cssRuleCode = document.all ? 'rules' : 'cssRules'; // account for IE and FF
|
||||
var StyleSheet = StyleSheets[Index];
|
||||
if(StyleSheet)
|
||||
{
|
||||
Result = StyleSheet[cssRuleCode];
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
GetOrSetRule(SelectorText)
|
||||
{
|
||||
var Result = GetRule(SelectorText);
|
||||
if(Result === undefined)
|
||||
{
|
||||
var StyleSheet = document.styleSheets[0];
|
||||
var RuleIndex = StyleSheet.insertRule(SelectorText + "{}", StyleSheet.length - 1);
|
||||
var Rules = GetRulesOfStyleSheetIndex(0);
|
||||
Result = Rules[RuleIndex];
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
/* Auto-scrolling */
|
||||
var LastScrollYPos = 0;
|
||||
var ScrollTicking = false;
|
||||
var ScrollerFunction;
|
||||
var ScrollCondition;
|
||||
|
||||
function ScrollTo(Element, ScrollPos) {
|
||||
var BoundingRect = Element.getBoundingClientRect();
|
||||
var Height = BoundingRect.height;
|
||||
var PercentageOfInView = 89;
|
||||
var GatherableHeight = Height * (1 - PercentageOfInView / 100);
|
||||
var ScrollY = BoundingRect.top;
|
||||
var YOffsetFromPage = getElementYOffsetFromPage(Element);
|
||||
var DesiredScroll = null;
|
||||
|
||||
if(ScrollY < 0)
|
||||
{
|
||||
ScrollY = ~ScrollY;
|
||||
if(ScrollY <= GatherableHeight)
|
||||
{
|
||||
DesiredScroll = YOffsetFromPage;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var LowerProtrusion = ScrollY - (window.innerHeight - Height);
|
||||
if(LowerProtrusion > 0 && LowerProtrusion <= GatherableHeight)
|
||||
{
|
||||
DesiredScroll = ScrollPos + LowerProtrusion;
|
||||
}
|
||||
}
|
||||
|
||||
if(DesiredScroll !== null)
|
||||
{
|
||||
window.scrollTo({
|
||||
top: DesiredScroll,
|
||||
behavior: "smooth"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function
|
||||
InitScrollEventListener(Element)
|
||||
{
|
||||
window.addEventListener('scroll', function() {
|
||||
if(ScrollCondition == undefined || ScrollCondition == true)
|
||||
{
|
||||
LastScrollYPos = window.scrollY;
|
||||
|
||||
if (!ScrollTicking) {
|
||||
window.requestAnimationFrame(function() {
|
||||
clearTimeout(ScrollerFunction);
|
||||
ScrollerFunction = setTimeout(ScrollTo, 2000, Element, LastScrollYPos);
|
||||
ScrollTicking = false;
|
||||
});
|
||||
|
||||
ScrollTicking = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
/* /Auto-scrolling */
|
||||
|
||||
function getElementXOffsetFromPage(el) {
|
||||
var left = 0;
|
||||
do {
|
||||
left += el.offsetLeft;
|
||||
} while (el = el.offsetParent);
|
||||
return left;
|
||||
}
|
||||
|
||||
function getElementYOffsetFromPage(el) {
|
||||
var top = 0;
|
||||
do {
|
||||
top += el.offsetTop;
|
||||
} while (el = el.offsetParent);
|
||||
return top;
|
||||
}
|
||||
|
||||
function
|
||||
MaxWidthOfElement(Element)
|
||||
{
|
||||
var Result = 0;
|
||||
var OriginalWidth = Element.style.width;
|
||||
Element.style.width = "100%";
|
||||
var Max = parseInt(window.getComputedStyle(Element).width);
|
||||
Element.style.width = "unset";
|
||||
var Default = parseInt(window.getComputedStyle(Element).width);
|
||||
Element.style.width = OriginalWidth;
|
||||
|
||||
if(Max > window.innerWidth || Max == Default)
|
||||
{
|
||||
Result = window.innerWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Max;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
MaxHeightOfElement(Element)
|
||||
{
|
||||
var Result = 0;
|
||||
var OriginalHeight = Element.style.height;
|
||||
Element.style.height = "100%";
|
||||
var Max = parseInt(window.getComputedStyle(Element).height);
|
||||
Element.style.height = "unset";
|
||||
var Default = parseInt(window.getComputedStyle(Element).height);
|
||||
Element.style.height = OriginalHeight;
|
||||
|
||||
if(Max > window.innerHeight || Max == Default)
|
||||
{
|
||||
Result = window.innerHeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
Result = Max;
|
||||
}
|
||||
return Result;
|
||||
}
|
||||
|
||||
function
|
||||
Clamp(EndA, N, EndB)
|
||||
{
|
||||
var Min = EndA < EndB ? EndA : EndB;
|
||||
var Max = EndA > EndB ? EndA : EndB;
|
||||
return N < Min ? Min : N > Max ? Max : N;
|
||||
}
|
||||
|
||||
function
|
||||
Clamp01(N)
|
||||
{
|
||||
return N < 0 ? 0 : N > 1 ? 1 : N;
|
||||
}
|
||||
|
||||
function
|
||||
Lerp(A, t, B)
|
||||
{
|
||||
return (1-t)*A + t*B;
|
||||
}
|
||||
|
||||
function
|
||||
IsOverflowed(Element)
|
||||
{
|
||||
return Element.scrollHeight > Element.clientHeight || Element.scrollWidth > Element.clientWidth;
|
||||
}
|
||||
|
||||
function
|
||||
BindHelp(Button, DocumentationContainer)
|
||||
{
|
||||
window.addEventListener("blur", function(){
|
||||
Button.firstElementChild.innerText = "¿";
|
||||
Button.firstElementChild.title = "Keypresses will not pass through to Cinera because focus is currently elsewhere.\n\nTo regain focus, please press Tab / Shift-Tab (multiple times) or click somewhere related to Cinera other than the video, e.g. this button";
|
||||
});
|
||||
|
||||
window.addEventListener("focus", function(){
|
||||
Button.firstElementChild.innerText = "?";
|
||||
Button.firstElementChild.title = ""
|
||||
});
|
||||
|
||||
Button.addEventListener("click", function() {
|
||||
DocumentationContainer.classList.toggle("visible");
|
||||
})
|
||||
}
|
||||
|
|
|
@ -1,642 +0,0 @@
|
|||
document.body.style.overflowY = "scroll";
|
||||
|
||||
if (location.hash && location.hash.length > 0) {
|
||||
var initialQuery = location.hash;
|
||||
if (initialQuery[0] == "#") {
|
||||
initialQuery = initialQuery.slice(1);
|
||||
}
|
||||
document.getElementById("query").value = decodeURIComponent(initialQuery);
|
||||
}
|
||||
|
||||
var indexControl = document.getElementById("cineraIndexControl");
|
||||
var indexSort = indexControl.querySelector("#cineraIndexSort");
|
||||
var indexSortChronological = true;
|
||||
|
||||
var filterMenu = indexControl.querySelector(".cineraIndexFilter");
|
||||
if(filterMenu)
|
||||
{
|
||||
var filterContainer = filterMenu.querySelector(".filter_container");
|
||||
//menuState.push(linkMenu);
|
||||
|
||||
filterMenu.addEventListener("mouseenter", function(ev) {
|
||||
filterContainer.style.display = "block";
|
||||
});
|
||||
|
||||
filterMenu.addEventListener("mouseleave", function(ev) {
|
||||
filterContainer.style.display = "none";
|
||||
});
|
||||
}
|
||||
|
||||
function hideEntriesOfProject(ProjectElement)
|
||||
{
|
||||
if(!ProjectElement.classList.contains("off"))
|
||||
{
|
||||
ProjectElement.classList.add("off");
|
||||
}
|
||||
var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
|
||||
var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value;
|
||||
var playerLocation = ProjectElement.attributes.getNamedItem("data-playerLocation").value;
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var ThisProject = projects[i];
|
||||
if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation && playerLocation === ThisProject.playerLocation)
|
||||
{
|
||||
ThisProject.filteredOut = true;
|
||||
if(ThisProject.entriesContainer != null)
|
||||
{
|
||||
ThisProject.entriesContainer.style.display = "none";
|
||||
disableSprite(ThisProject.entriesContainer.parentElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showEntriesOfProject(ProjectElement)
|
||||
{
|
||||
if(ProjectElement.classList.contains("off"))
|
||||
{
|
||||
ProjectElement.classList.remove("off");
|
||||
}
|
||||
var baseURL = ProjectElement.attributes.getNamedItem("data-baseURL").value;
|
||||
var searchLocation = ProjectElement.attributes.getNamedItem("data-searchLocation").value;
|
||||
var playerLocation = ProjectElement.attributes.getNamedItem("data-playerLocation").value;
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var ThisProject = projects[i];
|
||||
if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation && playerLocation === ThisProject.playerLocation)
|
||||
{
|
||||
ThisProject.filteredOut = false;
|
||||
if(ThisProject.entriesContainer != null)
|
||||
{
|
||||
ThisProject.entriesContainer.style.display = "flex";
|
||||
enableSprite(ThisProject.entriesContainer.parentElement);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function hideProjectSearchResults(baseURL, searchLocation, playerLocation)
|
||||
{
|
||||
var cineraResults = document.getElementById("cineraResults");
|
||||
if(cineraResults)
|
||||
{
|
||||
var cineraResultsProjects = cineraResults.querySelectorAll(".projectContainer");
|
||||
for(var i = 0; i < cineraResultsProjects.length; ++i)
|
||||
{
|
||||
var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value;
|
||||
var resultSearchLocation = cineraResultsProjects[i].attributes.getNamedItem("data-searchLocation").value;
|
||||
var resultPlayerLocation = cineraResultsProjects[i].attributes.getNamedItem("data-playerLocation").value;
|
||||
if(baseURL === resultBaseURL && searchLocation === resultSearchLocation && playerLocation === resultPlayerLocation)
|
||||
{
|
||||
cineraResultsProjects[i].style.display = "none";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function showProjectSearchResults(baseURL, searchLocation, playerLocation)
|
||||
{
|
||||
var cineraResults = document.getElementById("cineraResults");
|
||||
if(cineraResults)
|
||||
{
|
||||
var cineraResultsProjects = cineraResults.querySelectorAll(".projectContainer");
|
||||
for(var i = 0; i < cineraResultsProjects.length; ++i)
|
||||
{
|
||||
var resultBaseURL = cineraResultsProjects[i].attributes.getNamedItem("data-baseURL").value;
|
||||
var resultSearchLocation = cineraResultsProjects[i].attributes.getNamedItem("data-searchLocation").value;
|
||||
var resultPlayerLocation = cineraResultsProjects[i].attributes.getNamedItem("data-playerLocation").value;
|
||||
if(baseURL === resultBaseURL && searchLocation === resultSearchLocation && playerLocation === resultPlayerLocation)
|
||||
{
|
||||
cineraResultsProjects[i].style.display = "flex";
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggleEntriesOfProjectAndChildren(ProjectFilterElement)
|
||||
{
|
||||
var baseURL = ProjectFilterElement.attributes.getNamedItem("data-baseURL").value;
|
||||
var searchLocation = ProjectFilterElement.attributes.getNamedItem("data-searchLocation").value;
|
||||
var playerLocation = ProjectFilterElement.attributes.getNamedItem("data-playerLocation").value;
|
||||
var shouldShow = ProjectFilterElement.classList.contains("off");
|
||||
if(shouldShow)
|
||||
{
|
||||
ProjectFilterElement.classList.remove("off");
|
||||
enableSprite(ProjectFilterElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
ProjectFilterElement.classList.add("off");
|
||||
disableSprite(ProjectFilterElement);
|
||||
}
|
||||
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var ThisProject = projects[i];
|
||||
|
||||
if(baseURL === ThisProject.baseURL && searchLocation === ThisProject.searchLocation && playerLocation === ThisProject.playerLocation)
|
||||
{
|
||||
if(shouldShow)
|
||||
{
|
||||
ThisProject.filteredOut = false;
|
||||
enableSprite(ThisProject.projectTitleElement.parentElement);
|
||||
if(ThisProject.entriesContainer != null)
|
||||
{
|
||||
ThisProject.entriesContainer.style.display = "flex";
|
||||
}
|
||||
showProjectSearchResults(ThisProject.baseURL, ThisProject.searchLocation, ThisProject.playerLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThisProject.filteredOut = true;
|
||||
disableSprite(ThisProject.projectTitleElement.parentElement);
|
||||
if(ThisProject.entriesContainer != null)
|
||||
{
|
||||
ThisProject.entriesContainer.style.display = "none";
|
||||
}
|
||||
hideProjectSearchResults(ThisProject.baseURL, ThisProject.searchLocation, ThisProject.playerLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var indexChildFilterProjects = ProjectFilterElement.querySelectorAll(".cineraFilterProject");
|
||||
|
||||
for(var j = 0; j < indexChildFilterProjects.length; ++j)
|
||||
{
|
||||
var ThisElement = indexChildFilterProjects[j];
|
||||
var baseURL = ThisElement.attributes.getNamedItem("data-baseURL").value;
|
||||
var searchLocation = ThisElement.attributes.getNamedItem("data-searchLocation").value;
|
||||
var playerLocation = ThisElement.attributes.getNamedItem("data-playerLocation").value;
|
||||
if(shouldShow)
|
||||
{
|
||||
showEntriesOfProject(ThisElement);
|
||||
showProjectSearchResults(baseURL, searchLocation, playerLocation);
|
||||
}
|
||||
else
|
||||
{
|
||||
hideEntriesOfProject(ThisElement);
|
||||
hideProjectSearchResults(baseURL, searchLocation, playerLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var indexFilter = indexControl.querySelector(".cineraIndexFilter");
|
||||
if(indexFilter)
|
||||
{
|
||||
var indexFilterProjects = indexFilter.querySelectorAll(".cineraFilterProject");
|
||||
for(var i = 0; i < indexFilterProjects.length; ++i)
|
||||
{
|
||||
indexFilterProjects[i].addEventListener("mouseover", function(ev) {
|
||||
ev.stopPropagation();
|
||||
this.classList.add("focused");
|
||||
focusSprite(this);
|
||||
});
|
||||
indexFilterProjects[i].addEventListener("mouseout", function(ev) {
|
||||
ev.stopPropagation();
|
||||
this.classList.remove("focused");
|
||||
unfocusSprite(this);
|
||||
});
|
||||
indexFilterProjects[i].addEventListener("click", function(ev) {
|
||||
ev.stopPropagation();
|
||||
toggleEntriesOfProjectAndChildren(this);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
var resultsSummary = document.getElementById("cineraResultsSummary");
|
||||
var resultsContainer = document.getElementById("cineraResults");
|
||||
|
||||
var indexContainer = document.getElementById("cineraIndex");
|
||||
|
||||
var projectsContainer = indexContainer.querySelectorAll(".cineraIndexProject");
|
||||
|
||||
var projectContainerPrototype = document.createElement("DIV");
|
||||
projectContainerPrototype.classList.add("projectContainer");
|
||||
|
||||
var dayContainerPrototype = document.createElement("DIV");
|
||||
dayContainerPrototype.classList.add("dayContainer");
|
||||
|
||||
var dayNamePrototype = document.createElement("SPAN");
|
||||
dayNamePrototype.classList.add("dayName");
|
||||
dayContainerPrototype.appendChild(dayNamePrototype);
|
||||
|
||||
var markerListPrototype = document.createElement("DIV");
|
||||
markerListPrototype.classList.add("markerList");
|
||||
dayContainerPrototype.appendChild(markerListPrototype);
|
||||
|
||||
var markerPrototype = document.createElement("A");
|
||||
markerPrototype.classList.add("marker");
|
||||
if(resultsContainer.getAttribute("data-single") == 0)
|
||||
{
|
||||
markerPrototype.setAttribute("target", "_blank");
|
||||
}
|
||||
|
||||
function prepareToParseIndexFile(project)
|
||||
{
|
||||
project.xhr.addEventListener("load", function() {
|
||||
var contents = project.xhr.response;
|
||||
var lines = contents.split("\n");
|
||||
var mode = "none";
|
||||
var episode = null;
|
||||
for (var i = 0; i < lines.length; ++i) {
|
||||
var line = lines[i];
|
||||
if (line.trim().length == 0) { continue; }
|
||||
if (line == "---") {
|
||||
if (episode != null && episode.name != null && episode.title != null) {
|
||||
episode.filename = episode.name;
|
||||
episode.day = getEpisodeName(episode.filename + ".html.md");
|
||||
episode.dayContainerPrototype = project.dayContainerPrototype;
|
||||
episode.markerPrototype = markerPrototype;
|
||||
episode.playerURLPrefix = project.playerURLPrefix;
|
||||
project.episodes.push(episode);
|
||||
}
|
||||
episode = {};
|
||||
mode = "none";
|
||||
} else if (line.startsWith("name:")) {
|
||||
episode.name = line.slice(6);
|
||||
} else if (line.startsWith("title:")) {
|
||||
episode.title = line.slice(7).trim().slice(1, -1);
|
||||
} else if (line.startsWith("markers")) {
|
||||
mode = "markers";
|
||||
episode.markers = [];
|
||||
} else if (mode == "markers") {
|
||||
var match = line.match(/"(\d+)": "(.+)"/);
|
||||
if (match == null) {
|
||||
console.log(name, line);
|
||||
} else {
|
||||
var totalTime = parseInt(line.slice(1));
|
||||
var marker = {
|
||||
totalTime: totalTime,
|
||||
prettyTime: markerTime(totalTime),
|
||||
text: match[2].replace(/\\"/g, "\"")
|
||||
}
|
||||
episode.markers.push(marker);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.querySelector(".spinner").classList.remove("show");
|
||||
project.parsed = true;
|
||||
runSearch(true);
|
||||
});
|
||||
project.xhr.addEventListener("error", function() {
|
||||
console.error("Failed to load content");
|
||||
});
|
||||
}
|
||||
|
||||
var projects = [];
|
||||
function prepareProjects()
|
||||
{
|
||||
for(var i = 0; i < projectsContainer.length; ++i)
|
||||
{
|
||||
var ID = projectsContainer[i].attributes.getNamedItem("data-project").value;
|
||||
var baseURL = projectsContainer[i].attributes.getNamedItem("data-baseURL").value;
|
||||
var searchLocation = projectsContainer[i].attributes.getNamedItem("data-searchLocation").value;
|
||||
var playerLocation = projectsContainer[i].attributes.getNamedItem("data-playerLocation").value;
|
||||
var theme = projectsContainer[i].classList.item(1);
|
||||
|
||||
projects[i] =
|
||||
{
|
||||
baseURL: baseURL,
|
||||
searchLocation: searchLocation,
|
||||
playerLocation: playerLocation,
|
||||
playerURLPrefix: (baseURL ? baseURL + "/" : "") + (playerLocation ? playerLocation + "/" : ""),
|
||||
indexLocation: (baseURL ? baseURL + "/" : "") + (searchLocation ? searchLocation + "/" : "") + ID + ".index",
|
||||
projectTitleElement: projectsContainer[i].querySelector(":scope > .cineraProjectTitle"),
|
||||
entriesContainer: projectsContainer[i].querySelector(":scope > .cineraIndexEntries"),
|
||||
dayContainerPrototype: dayContainerPrototype.cloneNode(true),
|
||||
filteredOut: false,
|
||||
parsed: false,
|
||||
searched: false,
|
||||
resultsToRender: [],
|
||||
resultsIndex: 0,
|
||||
theme: theme,
|
||||
episodes: [],
|
||||
xhr: new XMLHttpRequest(),
|
||||
}
|
||||
|
||||
projects[i].dayContainerPrototype.classList.add(theme);
|
||||
projects[i].dayContainerPrototype.children[1].classList.add(theme);
|
||||
|
||||
document.querySelector(".spinner").classList.add("show");
|
||||
projects[i].xhr.open("GET", projects[i].indexLocation);
|
||||
projects[i].xhr.setRequestHeader("Content-Type", "text/plain");
|
||||
projects[i].xhr.send();
|
||||
prepareToParseIndexFile(projects[i]);
|
||||
}
|
||||
}
|
||||
prepareProjects();
|
||||
|
||||
indexSort.addEventListener("click", function(ev) {
|
||||
if(indexSortChronological)
|
||||
{
|
||||
this.firstChild.nodeValue = "Sort: New to Old ⏷"
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
if(projects[i].entriesContainer)
|
||||
{
|
||||
projects[i].entriesContainer.style.flexFlow = "column-reverse";
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
this.firstChild.nodeValue = "Sort: Old to New ⏶"
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
if(projects[i].entriesContainer)
|
||||
{
|
||||
projects[i].entriesContainer.style.flexFlow = "column";
|
||||
}
|
||||
}
|
||||
}
|
||||
indexSortChronological = !indexSortChronological;
|
||||
runSearch(true);
|
||||
});
|
||||
|
||||
var lastQuery = null;
|
||||
var markerList = null;
|
||||
var projectContainer = null;
|
||||
var resultsMarkerIndex = -1;
|
||||
var rendering = false;
|
||||
|
||||
var highlightPrototype = document.createElement("B");
|
||||
|
||||
function getEpisodeName(filename) {
|
||||
var day = filename;
|
||||
var dayParts = day.match(/([a-zA-Z_-]+)([0-9]+)?([a-zA-Z]+)?/);
|
||||
day = dayParts[1].slice(0, 1).toUpperCase() + dayParts[1].slice(1) + (dayParts[2] ? " " + dayParts[2] : "") + (dayParts[3] ? " " + dayParts[3].toUpperCase() : "");
|
||||
return day;
|
||||
}
|
||||
|
||||
function markerTime(totalTime) {
|
||||
var markTime = "(";
|
||||
var hours = Math.floor(totalTime / 60 / 60);
|
||||
var minutes = Math.floor(totalTime / 60) % 60;
|
||||
var seconds = totalTime % 60;
|
||||
if (hours > 0) {
|
||||
markTime += padTimeComponent(hours) + ":";
|
||||
}
|
||||
|
||||
markTime += padTimeComponent(minutes) + ":" + padTimeComponent(seconds) + ")";
|
||||
|
||||
return markTime;
|
||||
}
|
||||
|
||||
function padTimeComponent(component) {
|
||||
return (component < 10 ? "0" + component : component);
|
||||
}
|
||||
|
||||
function resetProjectsForSearch()
|
||||
{
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var project = projects[i];
|
||||
project.searched = false;
|
||||
project.resultsToRender = [];
|
||||
}
|
||||
}
|
||||
|
||||
var renderHandle;
|
||||
|
||||
function runSearch(refresh) {
|
||||
var queryStr = document.getElementById("query").value;
|
||||
if (refresh || lastQuery != queryStr) {
|
||||
var oldResultsContainer = resultsContainer;
|
||||
resultsContainer = oldResultsContainer.cloneNode(false);
|
||||
oldResultsContainer.parentNode.insertBefore(resultsContainer, oldResultsContainer);
|
||||
oldResultsContainer.remove();
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
projects[i].resultsIndex = 0;
|
||||
}
|
||||
resultsMarkerIndex = -1;
|
||||
}
|
||||
lastQuery = queryStr;
|
||||
|
||||
resetProjectsForSearch();
|
||||
|
||||
var numEpisodes = 0;
|
||||
var numMarkers = 0;
|
||||
var totalSeconds = 0;
|
||||
|
||||
// NOTE(matt): Function defined within runSearch() so that we can modify numEpisodes, numMarkers and totalSeconds
|
||||
function runSearchInterior(resultsToRender, query, episode)
|
||||
{
|
||||
var matches = [];
|
||||
for (var k = 0; k < episode.markers.length; ++k) {
|
||||
query.lastIndex = 0;
|
||||
var result = query.exec(episode.markers[k].text);
|
||||
if (result && result[0].length > 0) {
|
||||
numMarkers++;
|
||||
matches.push(episode.markers[k]);
|
||||
if (k < episode.markers.length-1) {
|
||||
totalSeconds += episode.markers[k+1].totalTime - episode.markers[k].totalTime;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (matches.length > 0) {
|
||||
numEpisodes++;
|
||||
resultsToRender.push({
|
||||
query: query,
|
||||
episode: episode,
|
||||
matches: matches
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (queryStr && queryStr.length > 0) {
|
||||
indexContainer.style.display = "none";
|
||||
resultsSummary.style.display = "block";
|
||||
var shouldRender = false;
|
||||
var query = new RegExp(queryStr.replace("(", "\\(").replace(")", "\\)").replace(/\|+/, "\|").replace(/\|$/, "").replace(/(^|[^\\])\\$/, "$1"), "gi");
|
||||
|
||||
// Visible
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var project = projects[i];
|
||||
if(project.parsed && !project.filteredOut && project.episodes.length > 0) {
|
||||
if(indexSortChronological)
|
||||
{
|
||||
for(var j = 0; j < project.episodes.length; ++j) {
|
||||
var episode = project.episodes[j];
|
||||
runSearchInterior(project.resultsToRender, query, episode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(var j = project.episodes.length; j > 0; --j) {
|
||||
var episode = project.episodes[j - 1];
|
||||
runSearchInterior(project.resultsToRender, query, episode);
|
||||
}
|
||||
}
|
||||
|
||||
shouldRender = true;
|
||||
project.searched = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Invisible
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var project = projects[i];
|
||||
if(project.parsed && project.filteredOut && !project.searched && project.episodes.length > 0) {
|
||||
if(indexSortChronological)
|
||||
{
|
||||
for(var j = 0; j < project.episodes.length; ++j) {
|
||||
var episode = project.episodes[j];
|
||||
runSearchInterior(project.resultsToRender, query, episode);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(var j = project.episodes.length; j > 0; --j) {
|
||||
var episode = project.episodes[j - 1];
|
||||
runSearchInterior(project.resultsToRender, query, episode);
|
||||
}
|
||||
}
|
||||
|
||||
shouldRender = true;
|
||||
project.searched = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if(shouldRender)
|
||||
{
|
||||
if (rendering) {
|
||||
clearTimeout(renderHandle);
|
||||
}
|
||||
renderResults();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
indexContainer.style.display = "block";
|
||||
resultsSummary.style.display = "none";
|
||||
}
|
||||
|
||||
var totalTime = Math.floor(totalSeconds/60/60) + "h " + Math.floor(totalSeconds/60)%60 + "m " + totalSeconds%60 + "s ";
|
||||
|
||||
resultsSummary.textContent = "Found: " + numEpisodes + " episodes, " + numMarkers + " markers, " + totalTime + "total.";
|
||||
}
|
||||
|
||||
function renderResults() {
|
||||
var maxItems = 42;
|
||||
var numItems = 0;
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
var project = projects[i];
|
||||
if (project.resultsIndex < project.resultsToRender.length) {
|
||||
rendering = true;
|
||||
while (numItems < maxItems && project.resultsIndex < project.resultsToRender.length) {
|
||||
var query = project.resultsToRender[project.resultsIndex].query;
|
||||
var episode = project.resultsToRender[project.resultsIndex].episode;
|
||||
var matches = project.resultsToRender[project.resultsIndex].matches;
|
||||
if (resultsMarkerIndex == -1) {
|
||||
if(project.resultsIndex == 0 || project.resultsToRender[project.resultsIndex - 1].episode.playerURLPrefix != episode.playerURLPrefix)
|
||||
{
|
||||
projectContainer = projectContainerPrototype.cloneNode(true);
|
||||
for(var i = 0; i < projects.length; ++i)
|
||||
{
|
||||
if(projects[i].playerURLPrefix === episode.playerURLPrefix)
|
||||
{
|
||||
projectContainer.setAttribute("data-baseURL", projects[i].baseURL);
|
||||
projectContainer.setAttribute("data-searchLocation", projects[i].searchLocation);
|
||||
projectContainer.setAttribute("data-playerLocation", projects[i].playerLocation);
|
||||
if(projects[i].filteredOut)
|
||||
{
|
||||
projectContainer.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
resultsContainer.appendChild(projectContainer);
|
||||
}
|
||||
else
|
||||
{
|
||||
projectContainer = resultsContainer.lastElementChild;
|
||||
}
|
||||
|
||||
|
||||
var dayContainer = episode.dayContainerPrototype.cloneNode(true);
|
||||
var dayName = dayContainer.children[0];
|
||||
markerList = dayContainer.children[1];
|
||||
dayName.textContent = episode.day + ": " + episode.title;
|
||||
projectContainer.appendChild(dayContainer);
|
||||
resultsMarkerIndex = 0;
|
||||
numItems++;
|
||||
}
|
||||
|
||||
while (numItems < maxItems && resultsMarkerIndex < matches.length) {
|
||||
var match = matches[resultsMarkerIndex];
|
||||
var marker = episode.markerPrototype.cloneNode(true);
|
||||
marker.setAttribute("href", episode.playerURLPrefix + episode.filename.replace(/"/g, "") + "/#" + match.totalTime);
|
||||
query.lastIndex = 0;
|
||||
var cursor = 0;
|
||||
var text = match.text;
|
||||
var result = null;
|
||||
marker.appendChild(document.createTextNode(match.prettyTime + " "));
|
||||
while (result = query.exec(text)) {
|
||||
if (result.index > cursor) {
|
||||
marker.appendChild(document.createTextNode(text.slice(cursor, result.index)));
|
||||
}
|
||||
var highlightEl = highlightPrototype.cloneNode();
|
||||
highlightEl.textContent = result[0];
|
||||
marker.appendChild(highlightEl);
|
||||
cursor = result.index + result[0].length;
|
||||
}
|
||||
|
||||
if (cursor < text.length) {
|
||||
marker.appendChild(document.createTextNode(text.slice(cursor, text.length)));
|
||||
}
|
||||
markerList.appendChild(marker);
|
||||
numItems++;
|
||||
resultsMarkerIndex++;
|
||||
}
|
||||
|
||||
if (resultsMarkerIndex == matches.length) {
|
||||
resultsMarkerIndex = -1;
|
||||
project.resultsIndex++;
|
||||
}
|
||||
}
|
||||
renderHandle = setTimeout(renderResults, 0);
|
||||
} else {
|
||||
rendering = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function IsVisible(el) {
|
||||
var xPos = 0;
|
||||
var yPos = 0;
|
||||
var Height = parseInt(getComputedStyle(el).height);
|
||||
|
||||
while (el) {
|
||||
if (el.tagName == "BODY") {
|
||||
var xScroll = el.scrollLeft || document.documentElement.scrollLeft;
|
||||
var yScroll = el.scrollTop || document.documentElement.scrollTop;
|
||||
|
||||
xPos += (el.offsetLeft - xScroll + el.clientLeft)
|
||||
yPos += (el.offsetTop - yScroll + el.clientTop)
|
||||
} else {
|
||||
xPos += (el.offsetLeft - el.scrollLeft + el.clientLeft);
|
||||
yPos += (el.offsetTop - el.scrollTop + el.clientTop);
|
||||
}
|
||||
|
||||
el = el.offsetParent;
|
||||
}
|
||||
return ((xPos > 0 && xPos < window.innerWidth) && (yPos > 0 && yPos + Height < window.innerHeight));
|
||||
}
|
||||
|
||||
var queryEl = document.getElementById("query");
|
||||
if(document.hasFocus() && IsVisible(queryEl)) { queryEl.focus(); }
|
||||
queryEl.addEventListener("input", function(ev) {
|
||||
history.replaceState(null, null, "#" + encodeURIComponent(queryEl.value));
|
||||
runSearch();
|
||||
});
|
||||
|
||||
runSearch();
|
||||
|
||||
// Testing
|
|
@ -0,0 +1,62 @@
|
|||
document.body.style.overflowY = "scroll";
|
||||
|
||||
// Element Selection
|
||||
//
|
||||
Nav.Nexus = document.getElementById("cineraIndex");
|
||||
Nav.Controls.Header = document.getElementById("cineraIndexControl");
|
||||
Nav.Controls.Sort = Nav.Controls.Header.querySelector(".cineraMenuItem.sort");
|
||||
Nav.Controls.View = Nav.Controls.Header.querySelector(".cineraMenuItem.view");
|
||||
Nav.Controls.Anim = Nav.Controls.Header.querySelector(".cineraMenuItem.anim");
|
||||
Nav.Controls.Save = Nav.Controls.Header.querySelector(".cineraMenuItem.save");
|
||||
Nav.Controls.Help = Nav.Nexus.querySelector(".cineraHelp");
|
||||
Nav.Controls.HelpDocumentation = Nav.Controls.Help.querySelector(".help_container");
|
||||
Nav.GridContainer = Nav.Nexus.querySelector(".cineraIndexGridContainer");
|
||||
Nav.Controls.GridTraversal.Header = Nav.GridContainer.querySelector(".cineraTraversal");
|
||||
Nav.Controls.GridTraversal.Ascend = Nav.Controls.GridTraversal.Header.querySelector(".cineraButton.ascension");
|
||||
Nav.Controls.GridTraversal.Prev = Nav.Controls.GridTraversal.Header.querySelector(".cineraButton.prev");
|
||||
Nav.Controls.GridTraversal.Next = Nav.Controls.GridTraversal.Header.querySelector(".cineraButton.next");
|
||||
|
||||
Search.QueryElement = document.getElementById("query");
|
||||
Search.ResultsSummary = document.getElementById("cineraResultsSummary");
|
||||
Search.ResultsContainer = document.getElementById("cineraResults");
|
||||
Search.IndexContainer = document.getElementById("cineraIndexList");
|
||||
Search.ProjectsContainer = Search.IndexContainer.querySelectorAll(".cineraIndexProject");
|
||||
//
|
||||
///
|
||||
|
||||
// NOTE(matt): Initialisation
|
||||
//
|
||||
if(CineraProps.IsMobile)
|
||||
{
|
||||
Nav.Nexus.classList.add("mobile");
|
||||
}
|
||||
InitTraversalStack();
|
||||
InitNexus();
|
||||
InitHelpKeys(Nav.Controls.HelpDocumentation);
|
||||
Nav.GridSize = ComputeOptimalGridSize();
|
||||
SetHelpKeyAvailability(Nav.GridSize);
|
||||
InitButtons(); // NOTE(matt): Also does "keydown" listeners, needed before UpdateButtons()
|
||||
UpdateButtons();
|
||||
|
||||
InitQuery(Search.QueryElement);
|
||||
InitPrototypes(Search.ResultsContainer);
|
||||
prepareProjects();
|
||||
|
||||
SyncNavState();
|
||||
//
|
||||
////
|
||||
|
||||
// NOTE(matt): Listeners
|
||||
//
|
||||
BindControls();
|
||||
InitResizeEventListener();
|
||||
InitOrientationChangeListener();
|
||||
InitScrollEventListener(Nav.Nexus);
|
||||
//
|
||||
////
|
||||
|
||||
// NOTE(matt): On-load Execution
|
||||
//
|
||||
runSearch();
|
||||
//
|
||||
////
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue