Compare commits
34 Commits
b6fb755d29
...
master
Author | SHA1 | Date |
---|---|---|
Matt Mascarenhas | 14dafa4abe | |
Matt Mascarenhas | 213bb2f882 | |
Matt Mascarenhas | 77aec74483 | |
Matt Mascarenhas | 6852d06e04 | |
Matt Mascarenhas | 52d6d989f8 | |
Matt Mascarenhas | df93674bf7 | |
Matt Mascarenhas | 026585e50b | |
Matt Mascarenhas | 9d5f0f9146 | |
Matt Mascarenhas | a7694d4c3b | |
Matt Mascarenhas | c9bf96c7aa | |
Matt Mascarenhas | 44a5008aa7 | |
Matt Mascarenhas | 6576a91d11 | |
Matt Mascarenhas | 1280142d45 | |
Matt Mascarenhas | 6b09247cd2 | |
Matt Mascarenhas | 554f7393ff | |
Matt Mascarenhas | e8ed2f0143 | |
Matt Mascarenhas | ac4b155e73 | |
Matt Mascarenhas | 0f15957cb5 | |
Matt Mascarenhas | 68d1469212 | |
Matt Mascarenhas | f321a6b6bf | |
Matt Mascarenhas | 6ea5cb6d22 | |
Matt Mascarenhas | 0825cbb5ff | |
Matt Mascarenhas | 6e9c7edd1d | |
Matt Mascarenhas | b8f143e350 | |
Matt Mascarenhas | f60cf3087f | |
Matt Mascarenhas | 1cf703e346 | |
Matt Mascarenhas | 26e304f62c | |
Matt Mascarenhas | 8dffa513cc | |
Matt Mascarenhas | e17c3aa78c | |
Matt Mascarenhas | 84a35b9ece | |
Matt Mascarenhas | ef9937e95b | |
Matt Mascarenhas | 652d8f186f | |
Matt Mascarenhas | 91c33c580b | |
Matt Mascarenhas | f7a6df994f |
202
README.md
202
README.md
|
@ -5,23 +5,26 @@ deployment
|
||||||
|
|
||||||
### Install the dependencies
|
### Install the dependencies
|
||||||
|
|
||||||
1. flex (for hmmlib)
|
1. curl
|
||||||
2. curl (for cinera)
|
|
||||||
|
|
||||||
### Download, and prepare the parser
|
### Download, and copy the parser into place
|
||||||
|
|
||||||
1. `git clone git@gitssh.handmade.network:Annotation-Pushers/Annotation-System.git`
|
1. `git clone https://git.handmade.network/Annotation-Pushers/Annotation-System.git`
|
||||||
2. `cd Annotation-System/hmmlib`
|
2. `cd Annotation-System/cinera`
|
||||||
3. `make`
|
3. `cp ../hmmlib2/hmmlib.h .`
|
||||||
4. `cp hmml.a hmmlib.h ../cinera/`
|
|
||||||
5. `cd ../cinera/`
|
|
||||||
|
|
||||||
Note: For each parser update, remember to make and copy it into place.
|
Note: For each parser update, remember to copy it into place.
|
||||||
|
|
||||||
### Build
|
### Build
|
||||||
|
|
||||||
1. `$SHELL cinera.c`
|
1. `$SHELL cinera.c`
|
||||||
|
|
||||||
|
### Configure
|
||||||
|
|
||||||
|
cinera -h
|
||||||
|
|
||||||
|
This documents the configuration file format and default settings.
|
||||||
|
|
||||||
### Configure the server
|
### Configure the server
|
||||||
|
|
||||||
If you enforce a strict Content Security Policy and X-Frame-Options in your
|
If you enforce a strict Content Security Policy and X-Frame-Options in your
|
||||||
|
@ -38,56 +41,24 @@ and [Hardening your HTTP response headers](https://scotthelme.co.uk/hardening-yo
|
||||||
|
|
||||||
### Run
|
### Run
|
||||||
|
|
||||||
#### Single Edition operation
|
cinera -c /path/to/config.conf
|
||||||
|
|
||||||
cinera test.hmml
|
|
||||||
|
|
||||||
This simply generates an HTML file (and updates `cinera_topics.css` if needed)
|
|
||||||
from `test.hmml` and outputs to `out.html` (configurable with -o).
|
|
||||||
|
|
||||||
#### Project Edition operation
|
|
||||||
|
|
||||||
cinera -p ProjectID
|
|
||||||
|
|
||||||
Setting the ProjectID with the `-p` flag triggers Project Edition. In this
|
|
||||||
edition _Cinera_ monitors the Project Input Directory for new, edited and
|
|
||||||
deleted .hmml files, and generates one table of contents / search page and a
|
|
||||||
player page each for valid sets of annotations (or removes them, if needed).
|
|
||||||
|
|
||||||
By default all directories - input and output - are set to the current working
|
|
||||||
directory. Typical operation will involve setting these flags:
|
|
||||||
|
|
||||||
-d Project Input Directory, the directory where the .hmml files reside
|
|
||||||
-r Asset Root Directory, path shallower than or equal to the CSS, Images and
|
|
||||||
JS directories
|
|
||||||
-R Asset Root URL, corresponding to the Root Directory
|
|
||||||
-c CSS Directory, relative to Root
|
|
||||||
-i Images Directory, relative to Root
|
|
||||||
-j JS Directory, relative to Root
|
|
||||||
-b Output Base Directory, location of the table of contents / search page
|
|
||||||
-B Output Base URL, corresponding to the Output Base Directory
|
|
||||||
-t Template Directory
|
|
||||||
-x Search Template Location, relative to Template Directory
|
|
||||||
-y Player Template Location, relative to Template Directory
|
|
||||||
|
|
||||||
#### Templates
|
#### Templates
|
||||||
|
|
||||||
*Search Template*
|
*(Global) Search Template*
|
||||||
- `<!-- __CINERA_INCLUDES__ -->` _to put inside your own `<head></head>`_
|
- `<!-- __CINERA_INCLUDES__ -->` _to put inside your own `<head></head>`_
|
||||||
- `<!-- __CINERA_SEARCH__ -->` _the table of contents and search functionality_
|
- `<!-- __CINERA_SEARCH__ -->` _the table of contents and search functionality_
|
||||||
|
|
||||||
*Player Template*
|
*Player Template*
|
||||||
- `<!-- __CINERA_INCLUDES__ -->` _to put inside your own `<head></head>`_
|
- `<!-- __CINERA_INCLUDES__ -->` _to put inside your own `<head></head>`_
|
||||||
- `<!-- __CINERA_MENUS__ -->`
|
|
||||||
- `<!-- __CINERA_PLAYER__ -->`
|
- `<!-- __CINERA_PLAYER__ -->`
|
||||||
- `<!-- __CINERA_SCRIPT__ -->` _must come after `<!-- __CINERA_MENUS__ -->` and `<!-- __CINERA_PLAYER__ -->`_
|
|
||||||
|
|
||||||
*Optional tags available for use in your Player Template*
|
*Optional tags available for use in your Player Template*
|
||||||
- `<!-- __CINERA_TITLE__ -->`
|
- `<!-- __CINERA_TITLE__ -->`
|
||||||
- `<!-- __CINERA_VIDEO_ID__ -->`
|
- `<!-- __CINERA_VIDEO_ID__ -->`
|
||||||
- `<!-- __CINERA_VOD_PLATFORM__ -->`
|
- `<!-- __CINERA_VOD_PLATFORM__ -->`
|
||||||
|
|
||||||
*Other tags available for use in either template*
|
*Other tags available for use in any template*
|
||||||
- Asset tags:
|
- Asset tags:
|
||||||
- `<!-- __CINERA_ASSET__ path.ext -->`
|
- `<!-- __CINERA_ASSET__ path.ext -->`
|
||||||
General purpose tag that outputs the URL of the specified asset
|
General purpose tag that outputs the URL of the specified asset
|
||||||
|
@ -96,28 +67,50 @@ directory. Typical operation will involve setting these flags:
|
||||||
General purpose tag that outputs the URL of the specified asset
|
General purpose tag that outputs the URL of the specified asset
|
||||||
relative to the Images Directory (-i)
|
relative to the Images Directory (-i)
|
||||||
- `<!-- __CINERA_CSS__ path.ext -->`
|
- `<!-- __CINERA_CSS__ path.ext -->`
|
||||||
Convenience tag that outputs a <link rel="stylesheet"...> node
|
Convenience tag that outputs a `<link rel="stylesheet"...>` node
|
||||||
for the specified asset relative to the CSS Directory (-c), for
|
for the specified asset relative to the CSS Directory (-c), for
|
||||||
use inside your <head> block
|
use inside your `<head>` block
|
||||||
- `<!-- __CINERA_JS__ path.ext -->`
|
- `<!-- __CINERA_JS__ path.ext -->`
|
||||||
Convenience tag that outputs a <script type="text/javascript"...>
|
Convenience tag that outputs a `<script type="text/javascript"...>`
|
||||||
node for the specified asset relative to the JS Directory (-j),
|
node for the specified asset relative to the JS Directory (-j),
|
||||||
for use wherever a <script> node is valid
|
for use wherever a `<script>` node is valid
|
||||||
The path.ext in these tags supports parent directories to locate the
|
The path.ext in these tags supports parent directories to locate the
|
||||||
asset file relative to its specified type directory (generic, CSS, image
|
asset file relative to its specified type directory (generic, CSS, image
|
||||||
or JS), including the "../" directory, and paths containing spaces must
|
or JS), including the "../" directory, and paths containing spaces must
|
||||||
be surrounded with double-quotes (\-escapable if the quoted path itself
|
be surrounded with double-quotes (\-escapable if the quoted path itself
|
||||||
contains double-quotes).
|
contains double-quotes).
|
||||||
|
|
||||||
All these asset tags additionally perform revving, appending a query
|
All these asset tags additionally perform versioning, appending a query string
|
||||||
string (-Q) and the file's checksum to the URL. Changes to a file
|
(-Q) and the file's checksum to the URL. Changes to a file trigger a rehash and
|
||||||
trigger a rehash and edit of all HTML pages citing this asset.
|
edit of all HTML pages citing this asset.
|
||||||
|
|
||||||
|
- Navigation / Menu tags:
|
||||||
|
- `<!-- __CINERA_NAV__ -->`
|
||||||
|
This menu will contain only the current project, its siblings and
|
||||||
|
subprojects of both the aforementioned
|
||||||
|
- `<!-- __CINERA_GLOBAL_NAV__ -->`
|
||||||
|
This menu will contain every project in the configuration
|
||||||
|
|
||||||
|
These navigation tags additionally take one parameter, e.g.
|
||||||
|
`<!-- __CINERA_NAV__ horizontal -->`:
|
||||||
|
- `dropdown`
|
||||||
|
A dropdown menu, that opens on hover
|
||||||
|
- `horizontal`
|
||||||
|
More-or-less the same as `dropdown`, but always open
|
||||||
|
- `plain`
|
||||||
|
A straightforward `<ul>` for you to style how you like
|
||||||
|
|
||||||
- `<!-- __CINERA_PROJECT__ -->`
|
- `<!-- __CINERA_PROJECT__ -->`
|
||||||
|
The project's `html_title` if configured, otherwise its `title`
|
||||||
|
- `<!-- __CINERA_PROJECT_PLAIN__ -->`
|
||||||
|
The project's `title`
|
||||||
- `<!-- __CINERA_PROJECT_ID__ -->`
|
- `<!-- __CINERA_PROJECT_ID__ -->`
|
||||||
|
- `<!-- __CINERA_PROJECT_LINEAGE__ -->`
|
||||||
|
The IDs of all projects from the root to the current project, separated
|
||||||
|
by a spaced-slash
|
||||||
- `<!-- __CINERA_SEARCH_URL__ -->`
|
- `<!-- __CINERA_SEARCH_URL__ -->`
|
||||||
- `<!-- __CINERA_THEME__ -->`
|
- `<!-- __CINERA_THEME__ -->`
|
||||||
- `<!-- __CINERA_URL__ -->` _Only really usable if BaseURL is set (-B)_
|
- `<!-- __CINERA_URL__ -->`
|
||||||
- `<!-- __CINERA_CUSTOM0__ -->`
|
- `<!-- __CINERA_CUSTOM0__ -->`
|
||||||
- `<!-- __CINERA_CUSTOM1__ -->`
|
- `<!-- __CINERA_CUSTOM1__ -->`
|
||||||
- `<!-- __CINERA_CUSTOM2__ -->`
|
- `<!-- __CINERA_CUSTOM2__ -->`
|
||||||
|
@ -135,106 +128,15 @@ invalid, _Cinera_ will tell you what's wrong.
|
||||||
|
|
||||||
#### Arguments
|
#### Arguments
|
||||||
|
|
||||||
Usage: ./cinera [option(s)] filename(s)
|
Usage: ./cinera [option(s)]
|
||||||
|
|
||||||
Options:
|
Options:
|
||||||
Paths: (advisedly universal, but may be set per-(sub)project as required)
|
-c <config file path>
|
||||||
-r <assets root directory>
|
Set the main config file path
|
||||||
Override default assets root directory (".")
|
Defaults to: $XDG_CONFIG_HOME/cinera/cinera.conf
|
||||||
-R <assets root URL>
|
-0
|
||||||
Override default assets root URL ("")
|
Dry-run mode. Parse and print the config, but do not modify the
|
||||||
IMPORTANT: -r and -R must correspond to the same location
|
filesystem
|
||||||
UNSUPPORTED: If you move files from RootDir, the RootURL should
|
|
||||||
correspond to the resulting location
|
|
||||||
|
|
||||||
-c <CSS directory path>
|
|
||||||
Override default CSS directory (""), relative to root
|
|
||||||
-i <images directory path>
|
|
||||||
Override default images directory (""), relative to root
|
|
||||||
-j <JS directory path>
|
|
||||||
Override default JS directory (""), relative to root
|
|
||||||
-Q <revved resources query string>
|
|
||||||
Override default query string ("r")
|
|
||||||
To disable revved resources, set an empty string with -Q ""
|
|
||||||
|
|
||||||
Project Settings:
|
|
||||||
-p <project ID>
|
|
||||||
Set the project ID, triggering PROJECT EDITION
|
|
||||||
-m <default medium>
|
|
||||||
Override default default medium ("programming")
|
|
||||||
Known project defaults:
|
|
||||||
bitwise: programming
|
|
||||||
book: research
|
|
||||||
coad: research
|
|
||||||
reader: research
|
|
||||||
riscy: programming
|
|
||||||
risc: speech
|
|
||||||
chat: speech
|
|
||||||
code: programming
|
|
||||||
intro-to-c: programming
|
|
||||||
misc: admin
|
|
||||||
ray: programming
|
|
||||||
hmdshow: speech
|
|
||||||
lecture: speech
|
|
||||||
stream: programming
|
|
||||||
special: programming
|
|
||||||
obbg: programming
|
|
||||||
sysadmin: admin
|
|
||||||
-s <style>
|
|
||||||
Set the style / theme, corresponding to a cinera__*.css file
|
|
||||||
This is equal to the "project" field in the HMML files by default
|
|
||||||
|
|
||||||
Project Input Paths
|
|
||||||
-d <annotations directory>
|
|
||||||
Override default annotations directory (".")
|
|
||||||
-t <templates directory>
|
|
||||||
Override default templates directory (".")
|
|
||||||
|
|
||||||
-x <search template location>
|
|
||||||
Set search template file path, either absolute or relative to
|
|
||||||
template directory, and enable integration
|
|
||||||
-y <player template location>
|
|
||||||
Set player template file path, either absolute or relative
|
|
||||||
to template directory, and enable integration
|
|
||||||
|
|
||||||
Project Output Paths
|
|
||||||
-b <base output directory>
|
|
||||||
Override project's default base output directory (".")
|
|
||||||
-B <base URL>
|
|
||||||
Override default base URL ("")
|
|
||||||
NOTE: This must be set, if -n or -a are to be used
|
|
||||||
|
|
||||||
-n <search location>
|
|
||||||
Override default search location (""), relative to base
|
|
||||||
-a <player location>
|
|
||||||
Override default player location (""), relative to base
|
|
||||||
NOTE: The PlayerURLPrefix is currently hardcoded in cinera.c but
|
|
||||||
will be configurable in the full configuration system
|
|
||||||
|
|
||||||
Single Edition Output Path
|
|
||||||
-o <output location>
|
|
||||||
Override default output player location ("out.html")
|
|
||||||
|
|
||||||
-1
|
|
||||||
Open search result links in the same browser tab
|
|
||||||
NOTE: Ideal for a guide embedded in an iframe
|
|
||||||
-f
|
|
||||||
Force integration with an incomplete template
|
|
||||||
-g
|
|
||||||
Ignore video privacy status
|
|
||||||
NOTE: For use with projects whose videos are known to all be public,
|
|
||||||
to save us having to check their privacy status
|
|
||||||
-q
|
|
||||||
Quit after syncing with annotation files in project input directory
|
|
||||||
UNSUPPORTED: This is likely to be removed in the future
|
|
||||||
-w
|
|
||||||
Force quote cache rebuild (memory aid: "wget")
|
|
||||||
|
|
||||||
-l <n>
|
|
||||||
Override default log level (0), where n is from 0 (terse) to 7 (verbose)
|
|
||||||
-u <seconds>
|
|
||||||
Override default update interval (4)
|
|
||||||
|
|
||||||
-e
|
-e
|
||||||
Display (examine) database and exit
|
Display (examine) database and exit
|
||||||
-v
|
-v
|
||||||
|
|
5646
cinera/cinera.c
5646
cinera/cinera.c
File diff suppressed because it is too large
Load Diff
|
@ -506,15 +506,16 @@ ul.cineraNavPlain li.current > a {
|
||||||
.cineraMenus > .cineraHelp,
|
.cineraMenus > .cineraHelp,
|
||||||
.cineraHelp {
|
.cineraHelp {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
box-sizing: content-box;
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
height: 6px;
|
height: .5rem;
|
||||||
|
width: .5rem;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
width: 6px;
|
|
||||||
margin: 2px;
|
margin: 2px;
|
||||||
font-size: .75rem;
|
font-size: .75rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
line-height: 6px;
|
line-height: .5rem;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
z-index: 64;
|
z-index: 64;
|
||||||
}
|
}
|
||||||
|
@ -539,6 +540,16 @@ ul.cineraNavPlain li.current > a {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cineraHelp .help_container .help_custom_index {
|
||||||
|
background-color: #159 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cineraHelp .help_container h2 .help_title_key {
|
||||||
|
padding: .2em;
|
||||||
|
border: 1px solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
.cineraHelp .help_container .help_key {
|
.cineraHelp .help_container .help_key {
|
||||||
box-sizing: content-box;
|
box-sizing: content-box;
|
||||||
font-family: Inconsolata;
|
font-family: Inconsolata;
|
||||||
|
@ -613,12 +624,11 @@ ul.cineraNavPlain li.current > a {
|
||||||
.cineraMenus > .menu .credits_container {
|
.cineraMenus > .menu .credits_container {
|
||||||
border: 1px solid;
|
border: 1px solid;
|
||||||
border-top: none;
|
border-top: none;
|
||||||
display: none;
|
z-index: -1; /* NOTE(matt): Using "display: none" to hide them proved problematic for scrolling non-visible menus */
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
right: 0;
|
right: 0;
|
||||||
top: 100%;
|
top: 100%;
|
||||||
z-index: 8;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.cineraMenus > .menu .refs,
|
.cineraMenus > .menu .refs,
|
||||||
|
@ -638,7 +648,7 @@ ul.cineraNavPlain li.current > a {
|
||||||
}
|
}
|
||||||
|
|
||||||
.cineraMenus > .menu .visible {
|
.cineraMenus > .menu .visible {
|
||||||
display: block;
|
z-index: 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cineraMenus > .menu > .refs .ref {
|
.cineraMenus > .menu > .refs .ref {
|
||||||
|
@ -736,6 +746,11 @@ ul.cineraNavPlain li.current > a {
|
||||||
margin-right: 4px;
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cineraMenus > .menu > .filter_container .filter_header {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.cineraMenus > .menu > .filter_container .filter_mode,
|
.cineraMenus > .menu > .filter_container .filter_mode,
|
||||||
.cineraMenus > .menu > .link_container #cineraLinkMode {
|
.cineraMenus > .menu > .link_container #cineraLinkMode {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -755,11 +770,13 @@ ul.cineraNavPlain li.current > a {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cineraMenus > .menu > .filter_container .filter_header .filter_titles,
|
||||||
.cineraMenus > .menu > .filter_container .filters {
|
.cineraMenus > .menu > .filter_container .filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row nowrap;
|
flex-flow: row nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cineraMenus > .menu > .filter_container .filter_header .filter_titles > *,
|
||||||
.cineraMenus > .menu > .filter_container .filters > * {
|
.cineraMenus > .menu > .filter_container .filters > * {
|
||||||
width: 50%;
|
width: 50%;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
|
@ -968,6 +985,7 @@ ul.cineraNavPlain li.current > a {
|
||||||
|
|
||||||
.cineraMenus > .menu > .filter_container .filter_content .category,
|
.cineraMenus > .menu > .filter_container .filter_content .category,
|
||||||
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent .cineraCategories .category {
|
.cineraPlayerContainer .markers_container > .markers .marker .cineraContent .cineraCategories .category {
|
||||||
|
box-sizing: content-box;
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
height: 5px;
|
height: 5px;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,40 +1,5 @@
|
||||||
var cinera = document.querySelector(".cinera");
|
|
||||||
var baseURL = location.hash ? (location.toString().substr(0, location.toString().length - location.hash.length)) : location;
|
var baseURL = location.hash ? (location.toString().substr(0, location.toString().length - location.hash.length)) : location;
|
||||||
|
|
||||||
var originalTextContent = {
|
|
||||||
TitleQuotes: null,
|
|
||||||
TitleReferences: null,
|
|
||||||
TitleCredits: null,
|
|
||||||
EpisodePrev: null,
|
|
||||||
EpisodeNext: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
var menuState = [];
|
|
||||||
var titleBar = cinera.querySelector(".cineraMenus");
|
|
||||||
var quotesMenu = null;
|
|
||||||
var referencesMenu = null;
|
|
||||||
var filterMenu = null;
|
|
||||||
var viewsMenu = null;
|
|
||||||
var linkMenu = null;
|
|
||||||
var creditsMenu = null;
|
|
||||||
var sourceMenus = null;
|
|
||||||
var helpButton = null;
|
|
||||||
var helpDocumentation = null;
|
|
||||||
|
|
||||||
// NOTE(matt): One set of markers per page. There is code to support multiple, which we may want to extend everywhere
|
|
||||||
var MarkersContainer = cinera.querySelector(".markers_container");
|
|
||||||
|
|
||||||
var views = {
|
|
||||||
REGULAR: 0,
|
|
||||||
THEATRE: 1,
|
|
||||||
SUPERTHEATRE: 2,
|
|
||||||
};
|
|
||||||
|
|
||||||
var devices = {
|
|
||||||
DESKTOP: 0,
|
|
||||||
MOBILE: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
var CineraProps = {
|
var CineraProps = {
|
||||||
C: null,
|
C: null,
|
||||||
V: views.REGULAR,
|
V: views.REGULAR,
|
||||||
|
@ -57,275 +22,19 @@ var CineraProps = {
|
||||||
};
|
};
|
||||||
CineraProps.O = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile);
|
CineraProps.O = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile);
|
||||||
|
|
||||||
if(titleBar)
|
|
||||||
{
|
|
||||||
quotesMenu = titleBar.querySelector(".quotes_container");
|
|
||||||
if(quotesMenu)
|
|
||||||
{
|
|
||||||
originalTextContent.TitleQuotes = quotesMenu.previousElementSibling.textContent;
|
|
||||||
menuState.push(quotesMenu);
|
|
||||||
var quoteItems = quotesMenu.querySelectorAll(".ref");
|
|
||||||
if(quoteItems)
|
|
||||||
{
|
|
||||||
for(var i = 0; i < quoteItems.length; ++i)
|
|
||||||
{
|
|
||||||
quoteItems[i].addEventListener("mouseenter", function(ev) {
|
|
||||||
mouseOverQuotes(this);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
}
|
|
||||||
var quoteTimecodes = quotesMenu.querySelectorAll(".refs .ref .ref_indices .timecode");
|
|
||||||
for (var i = 0; i < quoteTimecodes.length; ++i) {
|
|
||||||
quoteTimecodes[i].addEventListener("click", function(ev) {
|
|
||||||
if (player) {
|
|
||||||
var time = ev.currentTarget.getAttribute("data-timestamp");
|
|
||||||
mouseSkipToTimecode(player, time, ev);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
var lastFocusedQuote = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
referencesMenu = titleBar.querySelector(".references_container");
|
|
||||||
if(referencesMenu)
|
|
||||||
{
|
|
||||||
originalTextContent.TitleReferences = referencesMenu.previousElementSibling.textContent;
|
|
||||||
menuState.push(referencesMenu);
|
|
||||||
var referenceItems = referencesMenu.querySelectorAll(".ref");
|
|
||||||
if(referenceItems)
|
|
||||||
{
|
|
||||||
for(var i = 0; i < referenceItems.length; ++i)
|
|
||||||
{
|
|
||||||
referenceItems[i].addEventListener("mouseenter", function(ev) {
|
|
||||||
mouseOverReferences(this);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
var lastFocusedReference = null;
|
|
||||||
var lastFocusedIdentifier = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var refTimecodes = referencesMenu.querySelectorAll(".refs .ref .ref_indices .timecode");
|
|
||||||
for (var i = 0; i < refTimecodes.length; ++i) {
|
|
||||||
refTimecodes[i].addEventListener("click", function(ev) {
|
|
||||||
if (player) {
|
|
||||||
var time = ev.currentTarget.getAttribute("data-timestamp");
|
|
||||||
mouseSkipToTimecode(player, time, ev);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(referencesMenu || quotesMenu)
|
|
||||||
{
|
|
||||||
var refSources = titleBar.querySelectorAll(".refs .ref"); // This is for both quotes and refs
|
|
||||||
for (var i = 0; i < refSources.length; ++i) {
|
|
||||||
refSources[i].addEventListener("click", function(ev) {
|
|
||||||
if (player) {
|
|
||||||
player.pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
filterMenu = titleBar.querySelector(".filter_container");
|
|
||||||
if(filterMenu)
|
|
||||||
{
|
|
||||||
menuState.push(filterMenu);
|
|
||||||
var lastFocusedCategory = null;
|
|
||||||
var lastFocusedTopic = null;
|
|
||||||
var lastFocusedMedium = null;
|
|
||||||
|
|
||||||
var filter = filterMenu.parentNode;
|
|
||||||
|
|
||||||
var filterModeElement = filter.querySelector(".filter_mode");
|
|
||||||
filterModeElement.addEventListener("click", function(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
toggleFilterMode();
|
|
||||||
});
|
|
||||||
|
|
||||||
var filterMode = filterModeElement.classList[1];
|
|
||||||
var filterItems = filter.querySelectorAll(".filter_content");
|
|
||||||
|
|
||||||
var filterInitState = new Object();
|
|
||||||
var filterState = new Object();
|
|
||||||
for(var i = 0; i < filterItems.length; ++i)
|
|
||||||
{
|
|
||||||
filterItems[i].addEventListener("mouseenter", function(ev) {
|
|
||||||
navigateFilter(this);
|
|
||||||
})
|
|
||||||
|
|
||||||
filterItems[i].addEventListener("click", function(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
filterItemToggle(this);
|
|
||||||
});
|
|
||||||
|
|
||||||
var filterItemName = filterItems[i].classList.item(1);
|
|
||||||
if(filterItems[i].parentNode.classList.contains("filter_topics"))
|
|
||||||
{
|
|
||||||
filterInitState[filterItemName] = { "type" : "topic", "off": (filterItems[i].classList.item(2) == "off") };
|
|
||||||
filterState[filterItemName] = { "type" : "topic", "off": (filterItems[i].classList.item(2) == "off") };
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filterInitState[filterItemName] = { "type" : "medium", "off": (filterItems[i].classList.item(2) == "off") };
|
|
||||||
filterState[filterItemName] = { "type" : "medium", "off": (filterItems[i].classList.item(2) == "off") };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
viewsMenu = titleBar.querySelector(".views");
|
|
||||||
if(viewsMenu && !CineraProps.IsMobile)
|
|
||||||
{
|
|
||||||
menuState.push(viewsMenu);
|
|
||||||
var viewsContainer = viewsMenu.querySelector(".views_container");
|
|
||||||
viewsMenu.addEventListener("mouseenter", function(ev) {
|
|
||||||
handleMouseOverViewsMenu();
|
|
||||||
});
|
|
||||||
viewsMenu.addEventListener("mouseleave", function(ev) {
|
|
||||||
viewsContainer.style.display = "none";
|
|
||||||
});
|
|
||||||
|
|
||||||
var viewItems = viewsMenu.querySelectorAll(".view");
|
|
||||||
for(var i = 0; i < viewItems.length; ++i)
|
|
||||||
{
|
|
||||||
viewItems[i].addEventListener("click", function(ev) {
|
|
||||||
switch(this.getAttribute("data-id"))
|
|
||||||
{
|
|
||||||
case "regular":
|
|
||||||
case "theatre":
|
|
||||||
{
|
|
||||||
toggleTheatreMode();
|
|
||||||
} break;
|
|
||||||
case "super":
|
|
||||||
{
|
|
||||||
toggleSuperTheatreMode();
|
|
||||||
} break;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
linkMenu = titleBar.querySelector(".link_container");
|
|
||||||
linkTimestamp = true;
|
|
||||||
if(linkMenu)
|
|
||||||
{
|
|
||||||
menuState.push(linkMenu);
|
|
||||||
|
|
||||||
var linkMode = linkMenu.querySelector("#cineraLinkMode");
|
|
||||||
var link = linkMenu.querySelector("#cineraLink");
|
|
||||||
|
|
||||||
linkMode.addEventListener("click", function(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
toggleLinkMode(linkMode, link);
|
|
||||||
});
|
|
||||||
|
|
||||||
link.addEventListener("click", function(ev) {
|
|
||||||
CopyToClipboard(link);
|
|
||||||
toggleMenuVisibility(linkMenu);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
creditsMenu = titleBar.querySelector(".credits_container");
|
|
||||||
if(creditsMenu)
|
|
||||||
{
|
|
||||||
originalTextContent.TitleCredits = creditsMenu.previousElementSibling.textContent;
|
|
||||||
menuState.push(creditsMenu);
|
|
||||||
var lastFocusedCreditItem = null;
|
|
||||||
|
|
||||||
var creditItems = creditsMenu.querySelectorAll(".person, .support");
|
|
||||||
for(var i = 0; i < creditItems.length; ++i)
|
|
||||||
{
|
|
||||||
creditItems[i].addEventListener("mouseenter", function(ev) {
|
|
||||||
if(this != lastFocusedCreditItem)
|
|
||||||
{
|
|
||||||
lastFocusedCreditItem.classList.remove("focused");
|
|
||||||
unfocusSprite(lastFocusedCreditItem);
|
|
||||||
if(lastFocusedCreditItem.classList.contains("support"))
|
|
||||||
{
|
|
||||||
setSpriteLightness(lastFocusedCreditItem.firstChild);
|
|
||||||
}
|
|
||||||
lastFocusedCreditItem = this;
|
|
||||||
focusedElement = lastFocusedCreditItem;
|
|
||||||
focusedElement.classList.add("focused");
|
|
||||||
focusSprite(focusedElement);
|
|
||||||
if(focusedElement.classList.contains("support"))
|
|
||||||
{
|
|
||||||
setSpriteLightness(focusedElement.firstChild);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if(creditItems[i].tagName == "A")
|
|
||||||
{
|
|
||||||
creditItems[i].addEventListener("click", function(ev) {
|
|
||||||
if(player)
|
|
||||||
{
|
|
||||||
player.pause();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourceMenus = titleBar.querySelectorAll(".menu");
|
|
||||||
|
|
||||||
helpButton = titleBar.querySelector(".cineraHelp");
|
|
||||||
helpDocumentation = helpButton.querySelector(".help_container");
|
|
||||||
BindHelp(helpButton, helpDocumentation);
|
|
||||||
}
|
|
||||||
|
|
||||||
var focusedElement = null;
|
|
||||||
var focusedIdentifier = null;
|
|
||||||
|
|
||||||
var playerContainer = cinera.querySelector(".cineraPlayerContainer")
|
|
||||||
var prevEpisode = playerContainer.querySelector(".episodeMarker.prev");
|
|
||||||
if(prevEpisode) { originalTextContent.EpisodePrev = prevEpisode.firstChild.textContent; }
|
|
||||||
var nextEpisode = playerContainer.querySelector(".episodeMarker.next");
|
|
||||||
if(nextEpisode) { originalTextContent.EpisodeNext = nextEpisode.firstChild.textContent; }
|
|
||||||
var testMarkers = playerContainer.querySelectorAll(".marker");
|
|
||||||
|
|
||||||
// NOTE(matt): All the originalTextContent values must be set by this point, because the player's construction may need them
|
|
||||||
var MobileCineraContentRuleSelector = ".cinera.mobile .cineraPlayerContainer .markers_container > .markers .marker .cineraContent";
|
var MobileCineraContentRuleSelector = ".cinera.mobile .cineraPlayerContainer .markers_container > .markers .marker .cineraContent";
|
||||||
var MobileCineraContentRule = GetOrSetRule(MobileCineraContentRuleSelector);
|
var MobileCineraContentRule = GetOrSetRule(MobileCineraContentRuleSelector);
|
||||||
|
|
||||||
var MenuContainerRuleSelector = ".cineraMenus > .menu .quotes_container, .cineraMenus > .menu .references_container, .cineraMenus > .menu .filter_container, .cineraMenus > .menu .views_container, .cineraMenus > .menu .link_container, .cineraMenus > .menu .credits_container";
|
var MenuContainerRuleSelector = ".cineraMenus > .menu .quotes_container, .cineraMenus > .menu .references_container, .cineraMenus > .menu .filter_container, .cineraMenus > .menu .views_container, .cineraMenus > .menu .link_container, .cineraMenus > .menu .credits_container";
|
||||||
var MenuContainerRule = GetOrSetRule(MenuContainerRuleSelector);
|
var MenuContainerRule = GetOrSetRule(MenuContainerRuleSelector);
|
||||||
|
|
||||||
if(CineraProps.IsMobile)
|
var cinera = document.querySelector(".cinera");
|
||||||
{
|
var player = new Player(cinera, onRefChanged);
|
||||||
InitMobileStyle();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
var MenuMaxHeight = cinera.offsetHeight - titleBar.offsetHeight - 4;
|
|
||||||
MenuContainerRule.style.maxHeight = MenuMaxHeight + "px";
|
|
||||||
}
|
|
||||||
|
|
||||||
var player = new Player(playerContainer, onRefChanged);
|
|
||||||
|
|
||||||
if(CineraProps.IsMobile)
|
|
||||||
{
|
|
||||||
ConnectMobileControls(player);
|
|
||||||
}
|
|
||||||
|
|
||||||
var cineraViewStorageItem = "cineraView";
|
|
||||||
|
|
||||||
if(viewsMenu && localStorage.getItem(cineraViewStorageItem))
|
|
||||||
{
|
|
||||||
toggleTheatreMode();
|
|
||||||
}
|
|
||||||
|
|
||||||
InitScrollEventListener(cinera);
|
|
||||||
|
|
||||||
function
|
|
||||||
DelayedUpdateSize()
|
|
||||||
{
|
|
||||||
player.updateSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("resize", function() {
|
window.addEventListener("resize", function() {
|
||||||
if(CineraProps.IsMobile)
|
if(CineraProps.IsMobile)
|
||||||
{
|
{
|
||||||
setTimeout(DelayedUpdateSize, 512);
|
setTimeout(DelayedUpdateSize, 512, player);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -333,10 +42,10 @@ window.addEventListener("resize", function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
window.onorientationchange = function() {
|
screen.orientation.onchange = function() {
|
||||||
if(CineraProps.IsMobile)
|
if(CineraProps.IsMobile)
|
||||||
{
|
{
|
||||||
setTimeout(DelayedUpdateSize, 512);
|
setTimeout(DelayedUpdateSize, 512, player);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -351,43 +60,17 @@ document.addEventListener("keydown", function(ev) {
|
||||||
key = "capitalSpace";
|
key = "capitalSpace";
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!ev.getModifierState("Control") && handleKey(key) == true && focusedElement)
|
if(!ev.getModifierState("Control") && player.handleKey(key) == true && player.MenusFocused.Item)
|
||||||
{
|
{
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for(var i = 0; i < sourceMenus.length; ++i)
|
document.addEventListener("fullscreenchange", function() {
|
||||||
|
if(!document.fullscreenElement && CineraProps.V == views.SUPERTHEATRE)
|
||||||
{
|
{
|
||||||
sourceMenus[i].addEventListener("mouseenter", function(ev) {
|
CineraProps.V = views.THEATRE;
|
||||||
handleMenuTogglerInteraction(this, ev.type);
|
localStorage.setItem(player.cineraViewStorageItem, views.THEATRE);
|
||||||
})
|
player.updateSize();
|
||||||
sourceMenus[i].addEventListener("mouseleave", function(ev) {
|
|
||||||
handleMenuTogglerInteraction(this, ev.type);
|
|
||||||
})
|
|
||||||
sourceMenus[i].addEventListener("click", function(ev) {
|
|
||||||
handleMenuTogglerInteraction(this, ev.type);
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
var colouredItems = playerContainer.querySelectorAll(".author, .member, .project");
|
|
||||||
for(i = 0; i < colouredItems.length; ++i)
|
|
||||||
{
|
|
||||||
setTextLightness(colouredItems[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var topicDots = cinera.querySelectorAll(".category");
|
|
||||||
for(var i = 0; i < topicDots.length; ++i)
|
|
||||||
{
|
|
||||||
setDotLightness(topicDots[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastTimestampStorageItem = "cineraTimecode_" + window.location.pathname;
|
|
||||||
var lastTimestamp;
|
|
||||||
if(location.hash) {
|
|
||||||
player.setTimeThenPlay(location.hash.startsWith('#') ? location.hash.substr(1) : location.hash);
|
|
||||||
}
|
|
||||||
else if(lastTimestamp = localStorage.getItem(lastTimestampStorageItem))
|
|
||||||
{
|
|
||||||
player.setTimeThenPlay(lastTimestamp);
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -13,6 +13,9 @@ DeriveReliableWindowDimensions()
|
||||||
Y: null,
|
Y: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var ScrollPosX = window.scrollX;
|
||||||
|
var ScrollPosY = window.scrollY;
|
||||||
|
|
||||||
var DisplaySettings = [];
|
var DisplaySettings = [];
|
||||||
for(var i = 0; i < document.body.children.length; ++i)
|
for(var i = 0; i < document.body.children.length; ++i)
|
||||||
{
|
{
|
||||||
|
@ -40,6 +43,9 @@ DeriveReliableWindowDimensions()
|
||||||
Child.style.display = DisplaySettings.shift();
|
Child.style.display = DisplaySettings.shift();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ScrollTriggeredInternally = true;
|
||||||
|
window.scroll(ScrollPosX, ScrollPosY);
|
||||||
|
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +82,7 @@ function IsVisible(Element, WindowDim) {
|
||||||
function
|
function
|
||||||
GetRealOrientation(PreferredLandscape, IsMobile)
|
GetRealOrientation(PreferredLandscape, IsMobile)
|
||||||
{
|
{
|
||||||
var Result = window.orientation;
|
var Result = screen.orientation.angle;
|
||||||
var WindowDim = GetWindowDim(IsMobile);
|
var WindowDim = GetWindowDim(IsMobile);
|
||||||
if(WindowDim.Y > WindowDim.X)
|
if(WindowDim.Y > WindowDim.X)
|
||||||
{
|
{
|
||||||
|
@ -185,6 +191,12 @@ function enableSprite(Element)
|
||||||
}
|
}
|
||||||
|
|
||||||
function disableSprite(Element)
|
function disableSprite(Element)
|
||||||
|
{
|
||||||
|
if(Element.classList.contains("focused"))
|
||||||
|
{
|
||||||
|
focusSprite(Element);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
if(Element.classList.contains("cineraSprite"))
|
if(Element.classList.contains("cineraSprite"))
|
||||||
{
|
{
|
||||||
|
@ -196,6 +208,7 @@ function disableSprite(Element)
|
||||||
disableSprite(Element.children[i]);
|
disableSprite(Element.children[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function unfocusSprite(Element)
|
function unfocusSprite(Element)
|
||||||
{
|
{
|
||||||
|
@ -310,6 +323,7 @@ function IsInRangeEx(Min, N, Max)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Auto-scrolling */
|
/* Auto-scrolling */
|
||||||
|
var ScrollTriggeredInternally = false;
|
||||||
var LastScrollYPos = 0;
|
var LastScrollYPos = 0;
|
||||||
var ScrollTicking = false;
|
var ScrollTicking = false;
|
||||||
var ScrollerFunction;
|
var ScrollerFunction;
|
||||||
|
@ -376,7 +390,11 @@ function
|
||||||
InitScrollEventListener(Element, IsMobile, StickyObscuringElement)
|
InitScrollEventListener(Element, IsMobile, StickyObscuringElement)
|
||||||
{
|
{
|
||||||
window.addEventListener('scroll', function() {
|
window.addEventListener('scroll', function() {
|
||||||
if(ScrollCondition == undefined || ScrollCondition == true)
|
if(ScrollTriggeredInternally)
|
||||||
|
{
|
||||||
|
ScrollTriggeredInternally = false;
|
||||||
|
}
|
||||||
|
else if(ScrollCondition == undefined || ScrollCondition == true)
|
||||||
{
|
{
|
||||||
LastScrollYPos = window.scrollY;
|
LastScrollYPos = window.scrollY;
|
||||||
|
|
||||||
|
@ -503,17 +521,29 @@ IsOverflowed(Element)
|
||||||
return Element.scrollHeight > Element.clientHeight || Element.scrollWidth > Element.clientWidth;
|
return Element.scrollHeight > Element.clientHeight || Element.scrollWidth > Element.clientWidth;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function
|
||||||
|
SetHelpUnfocused(Button)
|
||||||
|
{
|
||||||
|
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";
|
||||||
|
}
|
||||||
|
|
||||||
|
function
|
||||||
|
SetHelpFocused(Button)
|
||||||
|
{
|
||||||
|
Button.firstElementChild.innerText = "?";
|
||||||
|
Button.firstElementChild.title = ""
|
||||||
|
}
|
||||||
|
|
||||||
function
|
function
|
||||||
BindHelp(Button, DocumentationContainer)
|
BindHelp(Button, DocumentationContainer)
|
||||||
{
|
{
|
||||||
window.addEventListener("blur", function(){
|
window.addEventListener("blur", function(){
|
||||||
Button.firstElementChild.innerText = "¿";
|
SetHelpUnfocused(Button);
|
||||||
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(){
|
window.addEventListener("focus", function(){
|
||||||
Button.firstElementChild.innerText = "?";
|
SetHelpFocused(Button);
|
||||||
Button.firstElementChild.title = ""
|
|
||||||
});
|
});
|
||||||
|
|
||||||
Button.addEventListener("click", function() {
|
Button.addEventListener("click", function() {
|
||||||
|
@ -521,45 +551,16 @@ BindHelp(Button, DocumentationContainer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function RGBtoHSL(colour)
|
|
||||||
{
|
|
||||||
var rgb = colour.slice(4, -1).split(", ");
|
|
||||||
var red = rgb[0];
|
|
||||||
var green = rgb[1];
|
|
||||||
var blue = rgb[2];
|
|
||||||
var min = Math.min(red, green, blue);
|
|
||||||
var max = Math.max(red, green, blue);
|
|
||||||
var chroma = max - min;
|
|
||||||
var hue = 0;
|
|
||||||
if(max == red)
|
|
||||||
{
|
|
||||||
hue = ((green - blue) / chroma) % 6;
|
|
||||||
}
|
|
||||||
else if(max == green)
|
|
||||||
{
|
|
||||||
hue = ((blue - red) / chroma) + 2;
|
|
||||||
}
|
|
||||||
else if(max == blue)
|
|
||||||
{
|
|
||||||
hue = ((red - green) / chroma) + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
var saturation = chroma / 255 * 100;
|
|
||||||
hue = (hue * 60) < 0 ? 360 + (hue * 60) : (hue * 60);
|
|
||||||
|
|
||||||
return [hue, saturation]
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBackgroundColourRGB(element) {
|
function getBackgroundColourRGB(element) {
|
||||||
var Colour = getComputedStyle(element).getPropertyValue("background-color");
|
var Colour = getComputedStyle(element).getPropertyValue("background-color");
|
||||||
var depth = 0;
|
var depth = 0;
|
||||||
while((Colour == "transparent" || Colour == "rgba(0, 0, 0, 0)") && depth <= 4)
|
while((Colour == "transparent" || Colour == "rgba(0, 0, 0, 0)") && element.parentElement && depth <= 4)
|
||||||
{
|
{
|
||||||
element = element.parentNode;
|
element = element.parentElement;
|
||||||
Colour = getComputedStyle(element).getPropertyValue("background-color");
|
Colour = getComputedStyle(element).getPropertyValue("background-color");
|
||||||
++depth;
|
++depth;
|
||||||
}
|
}
|
||||||
var Staging = Colour.slice(4, -1).split(", ");
|
var Staging = Colour.slice(Colour.indexOf("(") + 1, -1).split(", ");
|
||||||
var Result = {
|
var Result = {
|
||||||
R: parseInt(Staging[0]),
|
R: parseInt(Staging[0]),
|
||||||
G: parseInt(Staging[1]),
|
G: parseInt(Staging[1]),
|
||||||
|
@ -580,6 +581,8 @@ function setTextLightness(textElement)
|
||||||
{
|
{
|
||||||
var textHue = textElement.getAttribute("data-hue");
|
var textHue = textElement.getAttribute("data-hue");
|
||||||
var textSaturation = textElement.getAttribute("data-saturation");
|
var textSaturation = textElement.getAttribute("data-saturation");
|
||||||
|
if(textHue && textSaturation)
|
||||||
|
{
|
||||||
if(getBackgroundBrightness(textElement.parentNode) < 127)
|
if(getBackgroundBrightness(textElement.parentNode) < 127)
|
||||||
{
|
{
|
||||||
textElement.style.color = ("hsl(" + textHue + ", " + textSaturation + ", 76%)");
|
textElement.style.color = ("hsl(" + textHue + ", " + textSaturation + ", 76%)");
|
||||||
|
@ -589,19 +592,23 @@ function setTextLightness(textElement)
|
||||||
textElement.style.color = ("hsl(" + textHue + ", " + textSaturation + ", 24%)");
|
textElement.style.color = ("hsl(" + textHue + ", " + textSaturation + ", 24%)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function setDotLightness(topicDot)
|
function setDotLightness(topicDot)
|
||||||
{
|
{
|
||||||
var Hue = RGBtoHSL(getComputedStyle(topicDot).getPropertyValue("background-color"))[0];
|
var dotHue = topicDot.getAttribute("data-hue");
|
||||||
var Saturation = RGBtoHSL(getComputedStyle(topicDot).getPropertyValue("background-color"))[1];
|
var dotSaturation = topicDot.getAttribute("data-saturation");
|
||||||
|
if(dotHue && dotSaturation)
|
||||||
|
{
|
||||||
if(getBackgroundBrightness(topicDot.parentNode) < 127)
|
if(getBackgroundBrightness(topicDot.parentNode) < 127)
|
||||||
{
|
{
|
||||||
topicDot.style.backgroundColor = ("hsl(" + Hue + ", " + Saturation + "%, 76%)");
|
topicDot.style.backgroundColor = ("hsl(" + dotHue + ", " + dotSaturation + ", 76%)");
|
||||||
topicDot.style.borderColor = ("hsl(" + Hue + ", " + Saturation + "%, 76%)");
|
topicDot.style.borderColor = ("hsl(" + dotHue + ", " + dotSaturation + ", 76%)");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
topicDot.style.backgroundColor = ("hsl(" + Hue + ", " + Saturation + "%, 47%)");
|
topicDot.style.backgroundColor = ("hsl(" + dotHue + ", " + dotSaturation + ", 47%)");
|
||||||
topicDot.style.borderColor = ("hsl(" + Hue + ", " + Saturation + "%, 47%)");
|
topicDot.style.borderColor = ("hsl(" + dotHue + ", " + dotSaturation + ", 47%)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,11 +213,11 @@ function prepareToParseIndexFile(project)
|
||||||
mode = "markers";
|
mode = "markers";
|
||||||
episode.markers = [];
|
episode.markers = [];
|
||||||
} else if (mode == "markers") {
|
} else if (mode == "markers") {
|
||||||
var match = line.match(/"(\d+)": "(.+)"/);
|
var match = line.match(/"(\d+.\d+)": "(.+)"/);
|
||||||
if (match == null) {
|
if (match == null) {
|
||||||
console.log(name, line);
|
console.log(name, line);
|
||||||
} else {
|
} else {
|
||||||
var totalTime = parseInt(line.slice(1));
|
var totalTime = parseFloat(line.slice(1));
|
||||||
var marker = {
|
var marker = {
|
||||||
totalTime: totalTime,
|
totalTime: totalTime,
|
||||||
prettyTime: markerTime(totalTime),
|
prettyTime: markerTime(totalTime),
|
||||||
|
@ -292,7 +292,7 @@ function markerTime(totalTime) {
|
||||||
var markTime = "(";
|
var markTime = "(";
|
||||||
var hours = Math.floor(totalTime / 60 / 60);
|
var hours = Math.floor(totalTime / 60 / 60);
|
||||||
var minutes = Math.floor(totalTime / 60) % 60;
|
var minutes = Math.floor(totalTime / 60) % 60;
|
||||||
var seconds = totalTime % 60;
|
var seconds = Math.floor(totalTime) % 60;
|
||||||
if (hours > 0) {
|
if (hours > 0) {
|
||||||
markTime += padTimeComponent(hours) + ":";
|
markTime += padTimeComponent(hours) + ":";
|
||||||
}
|
}
|
||||||
|
@ -460,7 +460,7 @@ function runSearch(refresh) {
|
||||||
Search.ResultsSummary.style.display = "none";
|
Search.ResultsSummary.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
var totalTime = Math.floor(totalSeconds/60/60) + "h " + Math.floor(totalSeconds/60)%60 + "m " + totalSeconds%60 + "s ";
|
var totalTime = Math.floor(totalSeconds/60/60) + "h " + Math.floor(totalSeconds/60)%60 + "m " + Math.floor(totalSeconds)%60 + "s ";
|
||||||
|
|
||||||
Search.ResultsSummary.textContent = "Found: " + numEpisodes + " episodes, " + numMarkers + " markers, " + totalTime + "total.";
|
Search.ResultsSummary.textContent = "Found: " + numEpisodes + " episodes, " + numMarkers + " markers, " + totalTime + "total.";
|
||||||
}
|
}
|
||||||
|
@ -3817,6 +3817,8 @@ PseudoPushButton(Button)
|
||||||
function
|
function
|
||||||
ResizeFunction()
|
ResizeFunction()
|
||||||
{
|
{
|
||||||
|
var OriginalScrollX = scrollX;
|
||||||
|
var OriginalScrollY = scrollY;
|
||||||
CineraProps.Orientation = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile);
|
CineraProps.Orientation = GetRealOrientation(orientations.LANDSCAPE_LEFT, CineraProps.IsMobile);
|
||||||
if(CineraProps.IsMobile)
|
if(CineraProps.IsMobile)
|
||||||
{
|
{
|
||||||
|
@ -3841,7 +3843,7 @@ ResizeFunction()
|
||||||
PickListView();
|
PickListView();
|
||||||
// TODO(matt): Inform user that we've switched to the list view
|
// TODO(matt): Inform user that we've switched to the list view
|
||||||
}
|
}
|
||||||
ScrollToWithOffset(Nav.Nexus, 0);
|
scroll(OriginalScrollX, OriginalScrollY);
|
||||||
}
|
}
|
||||||
UpdateButtons();
|
UpdateButtons();
|
||||||
}
|
}
|
||||||
|
@ -3864,7 +3866,7 @@ InitResizeEventListener()
|
||||||
function
|
function
|
||||||
InitOrientationChangeListener()
|
InitOrientationChangeListener()
|
||||||
{
|
{
|
||||||
window.onorientationchange = function()
|
screen.orientation.onchange = function()
|
||||||
{
|
{
|
||||||
if(CineraProps.IsMobile)
|
if(CineraProps.IsMobile)
|
||||||
{
|
{
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
|
@ -24,6 +24,8 @@ typedef struct {
|
||||||
char* output;
|
char* output;
|
||||||
char* template;
|
char* template;
|
||||||
char* medium;
|
char* medium;
|
||||||
|
char* number;
|
||||||
|
char* cc_lang;
|
||||||
|
|
||||||
HMML_Credit* credits;
|
HMML_Credit* credits;
|
||||||
size_t credit_count;
|
size_t credit_count;
|
||||||
|
@ -74,7 +76,7 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int line;
|
int line;
|
||||||
|
|
||||||
int h, m, s;
|
int h, m, s, ms;
|
||||||
|
|
||||||
char* text;
|
char* text;
|
||||||
char* author;
|
char* author;
|
||||||
|
@ -469,7 +471,7 @@ next_attr:
|
||||||
|
|
||||||
static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
||||||
{
|
{
|
||||||
unsigned int h = 0, m = 0, s = 0;
|
unsigned int h = 0, m = 0, s = 0, ms = 0;
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
int count = sscanf(p->cursor, "[%u:%u%n", &m, &s, &offset);
|
int count = sscanf(p->cursor, "[%u:%u%n", &m, &s, &offset);
|
||||||
|
|
||||||
|
@ -483,7 +485,7 @@ static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
||||||
if(c == ':') {
|
if(c == ':') {
|
||||||
unsigned int tmp;
|
unsigned int tmp;
|
||||||
offset = 0;
|
offset = 0;
|
||||||
if(sscanf(p->cursor, ":%u]%n", &tmp, &offset) != 1 || offset == 0) {
|
if(sscanf(p->cursor, ":%u%n", &tmp, &offset) != 1 || offset == 0) {
|
||||||
_hmml_err(p, "Unable to parse 3-part timecode");
|
_hmml_err(p, "Unable to parse 3-part timecode");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +494,27 @@ static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
||||||
s = tmp;
|
s = tmp;
|
||||||
|
|
||||||
p->cursor += offset;
|
p->cursor += offset;
|
||||||
|
c = *p->cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(c == '.') {
|
||||||
|
unsigned int tmp;
|
||||||
|
offset = 0;
|
||||||
|
|
||||||
|
int non_number_chars = 2;
|
||||||
|
int digits_in_100 = 3;
|
||||||
|
int max_chars_to_parse = non_number_chars + digits_in_100;
|
||||||
|
|
||||||
|
if(sscanf(p->cursor, ".%u]%n", &tmp, &offset) != 1 || offset == 0 || offset > max_chars_to_parse) {
|
||||||
|
_hmml_err(p, "Unable to parse %u.5-part timecode", h ? 3 : 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int i = offset - non_number_chars; i < digits_in_100; ++i) {
|
||||||
|
tmp *= 10;
|
||||||
|
}
|
||||||
|
ms = tmp;
|
||||||
|
|
||||||
|
p->cursor += offset;
|
||||||
|
|
||||||
} else if(c != ']') {
|
} else if(c != ']') {
|
||||||
_hmml_err(p, "Unable to parse timecode");
|
_hmml_err(p, "Unable to parse timecode");
|
||||||
|
@ -499,6 +522,10 @@ static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
||||||
++p->cursor;
|
++p->cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(ms >= 1000) {
|
||||||
|
_hmml_err(p, "Milliseconds cannot exceed 999");
|
||||||
|
}
|
||||||
|
|
||||||
if(s >= 60) {
|
if(s >= 60) {
|
||||||
_hmml_err(p, "Seconds cannot exceed 59");
|
_hmml_err(p, "Seconds cannot exceed 59");
|
||||||
}
|
}
|
||||||
|
@ -510,6 +537,7 @@ static void _hmml_parse_timecode(struct _hmml_parser* p, HMML_Timestamp* ts)
|
||||||
ts->h = h;
|
ts->h = h;
|
||||||
ts->m = m;
|
ts->m = m;
|
||||||
ts->s = s;
|
ts->s = s;
|
||||||
|
ts->ms = ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void _hmml_store_marker(struct _hmml_parser* p, HMML_Timestamp* ts, char** out, char* text_mem, size_t text_mem_size)
|
static void _hmml_store_marker(struct _hmml_parser* p, HMML_Timestamp* ts, char** out, char* text_mem, size_t text_mem_size)
|
||||||
|
@ -734,7 +762,9 @@ static void _hmml_parse_video(struct _hmml_parser* p)
|
||||||
{ HSTR("id") , &p->out.metadata.id },
|
{ HSTR("id") , &p->out.metadata.id },
|
||||||
{ HSTR("template") , &p->out.metadata.template },
|
{ HSTR("template") , &p->out.metadata.template },
|
||||||
{ HSTR("medium") , &p->out.metadata.medium },
|
{ HSTR("medium") , &p->out.metadata.medium },
|
||||||
|
{ HSTR("number") , &p->out.metadata.number },
|
||||||
{ HSTR("output") , &p->out.metadata.output },
|
{ HSTR("output") , &p->out.metadata.output },
|
||||||
|
{ HSTR("cc_lang") , &p->out.metadata.cc_lang },
|
||||||
};
|
};
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -820,7 +850,7 @@ void hmml_free(HMML_Output* out)
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct HMML_Version hmml_version = {
|
const struct HMML_Version hmml_version = {
|
||||||
2, 0, 12
|
2, 0, 15
|
||||||
};
|
};
|
||||||
|
|
||||||
#undef HSTX
|
#undef HSTX
|
||||||
|
|
Loading…
Reference in New Issue