Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9c3ee5edf |
+4
-1
@@ -1,7 +1,10 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.10"
|
||||
- "0.12"
|
||||
- "4"
|
||||
- "5"
|
||||
- "6"
|
||||
- "7"
|
||||
before_script:
|
||||
- "node ./build.js doc"
|
||||
sudo: false
|
||||
|
||||
@@ -1,24 +1,6 @@
|
||||
This project is no longer being worked on.
|
||||
[](https://travis-ci.org/Arnavion/libjass)
|
||||
|
||||
You should probably use something else, like https://github.com/Dador/JavascriptSubtitlesOctopus
|
||||
|
||||
When I started libjass in 2011, I made a bet that offloading rendering to the DOM would eventually be the way to get fast and accurate rendering. CSS filter effects were about to be standardized. Regular JavaScript would've been too slow to do the fancy rendering that ASS requires. Surely letting the browser render text would be faster than parsing fonts in JS, computing the dimensions and margins for every rendered character, and blitting individual outline and shadow pixels to a canvas.
|
||||
|
||||
However CSS filter effects by themselves turned out to be inadequate to accurately render even the basics of ASS. SVG filters are more accurate, but are unoptimized or unsupported in all browsers since nobody really uses them (a vicious cycle). As such, both of them are unable to efficiently render the simplest and most common ASS feature - the elliptical border. The `feMorphology` SVG filter can only dilate to rectangles, so libjass has to stack many such rectangles of different sizes to approximate an ellipse. Big borders end up needing tens of such rectangles and a large gaussian blur, which brings even the mightiest browser's renderer to its single-threaded knees.
|
||||
|
||||
Layout also has problems. CSS doesn't provide an easy to way for a subtitle to push another subtitle away so that they don't overlap. It doesn't provide a line-breaking strategy that tries to equalize the lengths of the broken lines (what ASS calls smart line wrapping). Vertically centering things is still a nightmare - flexbox and CSS grid don't help because subtitles don't follow grids - so `\an4-6` were never properly implemented. These things *could* be solved by positioning the text manually, but this would've brought us back to the problem of parsing fonts and measuring text dimensions in JavaScript instead of letting the DOM handle it.
|
||||
|
||||
In 2013, asm.js became a way to use the original C renderers like libass, compiled to something that's not as fast as native C but still faster than regular JavaScript rendering. More recently, WASM has emerged as a more cross-platform and strongly-guaranteed way of doing this. Parsing fonts and computing dimensions is now a feasible prospect.
|
||||
|
||||
Because of this, I believe libjass's strategy of relying on the browser DOM is a dead end.
|
||||
|
||||
I'm happy to continue providing support and answering questions about the code on Github. Since this repository is archived, please ask by opening an issue at https://github.com/Arnavion/archived-repos-issues instead. The code in this repository is still available under APL-2.0. The ASS parser is functional regardless of the browser renderer. Feel free to fork this project, or incorporate its code into your own projects, under the terms of the license.
|
||||
|
||||
Thank you, the users who used libjass on your websites, opened issues, and contributed fixes. libjass was my first OSS project that I intended to be used by more people than me. I had fun working on it and learning about web dev.
|
||||
|
||||
----
|
||||
|
||||
libjass is a JavaScript library written in TypeScript to render ASS subs in the browser. [Check out the demo.](https://arnavion.github.io/libjass/demo/index.xhtml)
|
||||
libjass is a JavaScript library written in TypeScript to render ASS subs in the browser. [Check out the demo.](http://arnavion.github.io/libjass/demo/index.xhtml)
|
||||
|
||||
|
||||
### What's special about libjass?
|
||||
@@ -60,37 +42,37 @@ Only libjass.js and libjass.css are needed to use libjass on your website. The o
|
||||
|
||||
The API documentation is linked in the Links section below. Here's an overview:
|
||||
|
||||
* The [ASS.fromUrl()](https://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromUrl) function takes in a URL to an ASS script and returns a promise that resolves to an [ASS](https://arnavion.github.io/libjass/api.xhtml#libjass.ASS) object. This ASS object represents the script properties, the line styles and dialogue lines in it. Alternatively, you can use [ASS.fromString()](https://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromString) to convert a string of the script contents into an ASS object.
|
||||
* The [ASS.fromUrl()](http://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromUrl) function takes in a URL to an ASS script and returns a promise that resolves to an [ASS](http://arnavion.github.io/libjass/api.xhtml#libjass.ASS) object. This ASS object represents the script properties, the line styles and dialogue lines in it. Alternatively, you can use [ASS.fromString()](http://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromString) to convert a string of the script contents into an ASS object.
|
||||
|
||||
* Next, you initialize a renderer to render the subtitles. libjass ships with an easy-to-use renderer, the [DefaultRenderer](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.DefaultRenderer). It uses information from the ASS object to build up a series of div elements around the video tag. There is a wrapper (.libjass-subs) containing div's corresponding to the layers in the ASS script, and each layer has div's corresponding to the 9 alignment directions. libjass.css contains styles for these div's to render them at the correct location.
|
||||
* Next, you initialize a renderer to render the subtitles. libjass ships with an easy-to-use renderer, the [DefaultRenderer](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.DefaultRenderer). It uses information from the ASS object to build up a series of div elements around the video tag. There is a wrapper (.libjass-subs) containing div's corresponding to the layers in the ASS script, and each layer has div's corresponding to the 9 alignment directions. libjass.css contains styles for these div's to render them at the correct location.
|
||||
|
||||
* The renderer uses [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window.requestAnimationFrame) as a source of timer ticks. In each tick, it determines the set of dialogues to be shown at the current video time, renders each of them as a div, and appendChild's the div into the appropriate layer+alignment div.
|
||||
|
||||
* The renderer can be told to dynamically change the size of the subtitles based on user input by calling [WebRenderer.resize()](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.WebRenderer.resize)
|
||||
* The renderer can be told to dynamically change the size of the subtitles based on user input by calling [WebRenderer.resize()](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.WebRenderer.resize)
|
||||
|
||||
* Lastly, the renderer contains an implementation of preloading fonts before playing the video. It uses a map of font names to URLs - this map can be conveniently created from a CSS file containing @font-face rules using [RendererSettings.makeFontMapFromStyleElement()](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.RendererSettings.makeFontMapFromStyleElement)
|
||||
* Lastly, the renderer contains an implementation of preloading fonts before playing the video. It uses a map of font names to URLs - this map can be conveniently created from a CSS file containing @font-face rules using [RendererSettings.makeFontMapFromStyleElement()](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.RendererSettings.makeFontMapFromStyleElement)
|
||||
|
||||
* For an example of using libjass, check out [the demo.](https://arnavion.github.io/libjass/demo/index.xhtml) It has comments explaining basic usage and pointers to some advanced usage.
|
||||
* For an example of using libjass, check out [the demo.](http://arnavion.github.io/libjass/demo/index.xhtml) It has comments explaining basic usage and pointers to some advanced usage.
|
||||
|
||||
|
||||
### What browser and JavaScript features does libjass need?
|
||||
|
||||
* libjass uses some ES5 features like getters and setters (via Object.defineProperty), and assumptions like the behavior of parseInt with leading zeros. It cannot be used with an ES3 environment.
|
||||
|
||||
* libjass will use ES6 Set, Map and Promise if they're available on the global object. If they're not present, it will use its own minimal internal implementations. If you have implementations of these that you would like libjass to use but don't want to register them on the global object, you can provide them to libjass specifically by setting the [libjass.Set](https://arnavion.github.io/libjass/api.xhtml#libjass.Set), [libjass.Map](https://arnavion.github.io/libjass/api.xhtml#libjass.Map) and [libjass.Promise](https://arnavion.github.io/libjass/api.xhtml#libjass.Promise) properties.
|
||||
* libjass will use ES6 Set, Map and Promise if they're available on the global object. If they're not present, it will use its own minimal internal implementations. If you have implementations of these that you would like libjass to use but don't want to register them on the global object, you can provide them to libjass specifically by setting the [libjass.Set](http://arnavion.github.io/libjass/api.xhtml#libjass.Set), [libjass.Map](http://arnavion.github.io/libjass/api.xhtml#libjass.Map) and [libjass.Promise](http://arnavion.github.io/libjass/api.xhtml#libjass.Promise) properties.
|
||||
|
||||
* [AutoClock](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.AutoClock) and [VideoClock](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.VideoClock) use [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) to generate clock ticks.
|
||||
* [AutoClock](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.AutoClock) and [VideoClock](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.VideoClock) use [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) to generate clock ticks.
|
||||
|
||||
* [WebRenderer](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.WebRenderer) and [DefaultRenderer](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.DefaultRenderer) use [SVG filter effects for HTML](https://caniuse.com/#feat=svg-html) to render outlines and blur. This feature is not available on all browsers, so you can tell them to fall back to more widely available CSS methods by setting the [RendererSettings.enableSvg](https://arnavion.github.io/libjass/api.xhtml#libjass.renderers.RendererSettings.enableSvg) property to false.
|
||||
* [WebRenderer](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.WebRenderer) and [DefaultRenderer](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.DefaultRenderer) use [SVG filter effects for HTML](http://caniuse.com/#feat=svg-html) to render outlines and blur. This feature is not available on all browsers, so you can tell them to fall back to more widely available CSS methods by setting the [RendererSettings.enableSvg](http://arnavion.github.io/libjass/api.xhtml#libjass.renderers.RendererSettings.enableSvg) property to false.
|
||||
|
||||
* WebRenderer and DefaultRenderer use [CSS3 animations](https://caniuse.com/#feat=css-animation) for effects like \mov and \fad.
|
||||
* WebRenderer and DefaultRenderer use [CSS3 animations](http://caniuse.com/#feat=css-animation) for effects like \mov and \fad.
|
||||
|
||||
* Using fonts attached to the script requires [ES6 typed arrays](https://caniuse.com/#feat=typedarrays) (ArrayBuffer, DataView, Uint8Array, etc).
|
||||
* Using fonts attached to the script requires [ES6 typed arrays](http://caniuse.com/#feat=typedarrays) (ArrayBuffer, DataView, Uint8Array, etc).
|
||||
|
||||
|
||||
### Can I use libjass in node?
|
||||
|
||||
libjass's parser works in node. Entire scripts can be parsed via [ASS.fromString()](https://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromString)
|
||||
libjass's parser works in node. Entire scripts can be parsed via [ASS.fromString()](http://arnavion.github.io/libjass/api.xhtml#libjass.ASS.fromString)
|
||||
|
||||
```javascript
|
||||
> var libjass = require("libjass")
|
||||
@@ -113,7 +95,7 @@ true
|
||||
'Fade { start: 0.2, end: 0 }'
|
||||
```
|
||||
|
||||
[libjass.parser.parse](https://arnavion.github.io/libjass/api.xhtml#libjass.parser.parse) parses the first parameter using the second parameter as the rule name. For example, the [dialogueParts](https://arnavion.github.io/libjass/api.xhtml#./parser/parse.ParserRun.parse_dialogueParts) rule can be used to get an array of [libjass.parts](https://arnavion.github.io/libjass/api.xhtml#libjass.parts) objects that represent the parts of an ASS dialogue line.
|
||||
[libjass.parser.parse](http://arnavion.github.io/libjass/api.xhtml#libjass.parser.parse) parses the first parameter using the second parameter as the rule name. For example, the [dialogueParts](http://arnavion.github.io/libjass/api.xhtml#./parser/parse.ParserRun.parse_dialogueParts) rule can be used to get an array of [libjass.parts](http://arnavion.github.io/libjass/api.xhtml#libjass.parts) objects that represent the parts of an ASS dialogue line.
|
||||
|
||||
```javascript
|
||||
> var parts = libjass.parser.parse("{\\an8}Are {\\i1}you{\\i0} the one who stole the clock?!", "dialogueParts")
|
||||
@@ -130,11 +112,18 @@ true
|
||||
8
|
||||
```
|
||||
|
||||
The rule names are derived from the methods on the [ParserRun class](https://arnavion.github.io/libjass/api.xhtml#./parser/parse.ParserRun).
|
||||
The rule names are derived from the methods on the [ParserRun class](http://arnavion.github.io/libjass/api.xhtml#./parser/parse.ParserRun).
|
||||
|
||||
See the tests, particularly the ones in tests/unit/miscellaneous.js, for examples.
|
||||
|
||||
|
||||
### Can I contribute?
|
||||
|
||||
Yes! Feature requests, suggestions, bug reports and pull requests are welcome! I'm especially looking for details and edge-cases of the ASS syntax that libjass doesn't support.
|
||||
|
||||
You can also join the IRC channel in the links section below and ask any questions.
|
||||
|
||||
|
||||
### Supported features
|
||||
|
||||
* Styles: Italic, Bold, Underline, StrikeOut, FontName, FontSize, ScaleX, ScaleY, Spacing, PrimaryColor, OutlineColor, BackColor, Outline, Shadow, Alignment, MarginL, MarginR, MarginV
|
||||
@@ -154,7 +143,8 @@ See the tests, particularly the ones in tests/unit/miscellaneous.js, for example
|
||||
### Links
|
||||
|
||||
* [GitHub](https://github.com/Arnavion/libjass/)
|
||||
* [API documentation](https://arnavion.github.io/libjass/api.xhtml)
|
||||
* IRC channel - #libjass on irc.rizon.net
|
||||
* [API documentation](http://arnavion.github.io/libjass/api.xhtml)
|
||||
* [Aegisub's documentation on ASS](http://docs.aegisub.org/3.0/ASS_Tags/)
|
||||
|
||||
|
||||
|
||||
@@ -82,8 +82,6 @@ task("version.ts", function (callback) {
|
||||
var versionString = packageJson.version;
|
||||
var versionParts = versionString.split(".").map(function (num) { return parseInt(num); });
|
||||
var versionFileContents =
|
||||
"/* tslint:disable */\n" +
|
||||
"\n" +
|
||||
"/**\n" +
|
||||
" * The version of libjass. An array like\n" +
|
||||
" *\n" +
|
||||
|
||||
+1
-2
@@ -12,8 +12,7 @@
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "classic",
|
||||
"noImplicitUseStrict": false,
|
||||
"types": []
|
||||
"noImplicitUseStrict": false
|
||||
},
|
||||
|
||||
"files": [
|
||||
|
||||
@@ -237,6 +237,7 @@ function addJSDocComments(modules: { [name: string]: AST.Module }): void {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
class FakeSourceFile {
|
||||
public text: string;
|
||||
public lineMap: number[];
|
||||
@@ -277,9 +278,11 @@ class FakeSourceFile {
|
||||
}
|
||||
|
||||
var fakeSourceFiles: { [name: string]: FakeSourceFile } = Object.create(null);
|
||||
*/
|
||||
|
||||
export const oldGetLeadingCommentRangesOfNodeFromText: typeof ts.getLeadingCommentRangesOfNodeFromText = ts.getLeadingCommentRangesOfNodeFromText.bind(ts);
|
||||
|
||||
/*
|
||||
ts.getLeadingCommentRangesOfNodeFromText = (node: ts.Node, text: string) => {
|
||||
const originalComments = oldGetLeadingCommentRangesOfNodeFromText(node, text);
|
||||
|
||||
@@ -297,12 +300,13 @@ ts.getLeadingCommentRangesOfNodeFromText = (node: ts.Node, text: string) => {
|
||||
};
|
||||
|
||||
var oldWriteCommentRange: typeof ts.writeCommentRange = ts.writeCommentRange.bind(ts);
|
||||
ts.writeCommentRange = (text: string, lineMap: number[], writer: ts.EmitTextWriter, comment: ts.CommentRange, newLine: string) => {
|
||||
ts.writeCommentRange = (text: string, lineMap: number[], writer: ts.EmitTextWriter, commentPos: number, commentEnd: number, newLine: string) => {
|
||||
if ((<{ sourceFile: ts.SourceFile }><any>comment).sourceFile) {
|
||||
const currentSourceFile = (<{ sourceFile: ts.SourceFile }><any>comment).sourceFile;
|
||||
text = currentSourceFile.text;
|
||||
lineMap = currentSourceFile.lineMap;
|
||||
}
|
||||
|
||||
return oldWriteCommentRange(text, lineMap, writer, comment, newLine);
|
||||
return oldWriteCommentRange(text, lineMap, writer, commentPos, commentEnd, newLine);
|
||||
};
|
||||
*/
|
||||
|
||||
Vendored
+1
@@ -19,4 +19,5 @@ declare namespace ts {
|
||||
function getTextOfNode(node: Node, includeTrivia?: boolean): string;
|
||||
function normalizeSlashes(path: string): string;
|
||||
function writeCommentRange(text: string, lineMap: number[], writer: EmitTextWriter, comment: CommentRange, newLine: string): void;
|
||||
function hasModifier(node: Node, flags: ModifierFlags): boolean;
|
||||
}
|
||||
|
||||
+29
-38
@@ -25,10 +25,6 @@ import { Compiler, oldGetLeadingCommentRangesOfNodeFromText } from "./compiler";
|
||||
|
||||
import * as AST from "./ast";
|
||||
|
||||
function hasModifier(node: ts.Node, flags: ts.NodeFlags): boolean {
|
||||
return (node.flags & flags) !== 0;
|
||||
}
|
||||
|
||||
interface JSDoc {
|
||||
description: string;
|
||||
isAbstract: boolean;
|
||||
@@ -186,7 +182,7 @@ class Walker {
|
||||
}
|
||||
|
||||
private _visitProperty(node: ts.PropertyDeclaration, parent: AST.Class | AST.Interface) {
|
||||
if (hasModifier(node, ts.NodeFlags.Private)) {
|
||||
if (ts.hasModifier(node, ts.ModifierFlags.Private)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -216,9 +212,9 @@ class Walker {
|
||||
jsDoc.returnType = new AST.ReturnType("", "*");
|
||||
}
|
||||
|
||||
const isPrivate = hasModifier(node, ts.NodeFlags.Private);
|
||||
const isProtected = hasModifier(node, ts.NodeFlags.Protected);
|
||||
const isStatic = hasModifier(node, ts.NodeFlags.Static);
|
||||
const isPrivate = ts.hasModifier(node, ts.ModifierFlags.Private);
|
||||
const isProtected = ts.hasModifier(node, ts.ModifierFlags.Protected);
|
||||
const isStatic = ts.hasModifier(node, ts.ModifierFlags.Static);
|
||||
|
||||
const generics = this._getGenericsOfSignatureDeclaration(node);
|
||||
|
||||
@@ -232,7 +228,7 @@ class Walker {
|
||||
|
||||
const name = ts.getTextOfNode(node.name);
|
||||
|
||||
const isPrivate = hasModifier(node, ts.NodeFlags.Private);
|
||||
const isPrivate = ts.hasModifier(node, ts.ModifierFlags.Private);
|
||||
|
||||
let property = clazz.members[name] as AST.Property;
|
||||
if (property === undefined) {
|
||||
@@ -255,7 +251,7 @@ class Walker {
|
||||
|
||||
const name = ts.getTextOfNode(node.name);
|
||||
|
||||
const isPrivate = hasModifier(node, ts.NodeFlags.Private);
|
||||
const isPrivate = ts.hasModifier(node, ts.ModifierFlags.Private);
|
||||
|
||||
let property = clazz.members[name] as AST.Property;
|
||||
if (property === undefined) {
|
||||
@@ -279,7 +275,7 @@ class Walker {
|
||||
}
|
||||
|
||||
const declaration = node.declarationList.declarations[0];
|
||||
if (hasModifier(declaration, ts.NodeFlags.Ambient)) {
|
||||
if (ts.hasModifier(declaration, ts.ModifierFlags.Ambient)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -299,7 +295,7 @@ class Walker {
|
||||
private _visitFunctionDeclaration(node: ts.FunctionDeclaration, parent: AST.Module): void {
|
||||
const jsDoc = this._parseJSDoc(node);
|
||||
|
||||
const isPrivate = !hasModifier(node, ts.NodeFlags.Export);
|
||||
const isPrivate = !ts.hasModifier(node, ts.ModifierFlags.Export);
|
||||
|
||||
const generics = this._getGenericsOfSignatureDeclaration(node);
|
||||
|
||||
@@ -344,7 +340,7 @@ class Walker {
|
||||
this._getGenericsOfTypeReferenceNode(type, generics)
|
||||
));
|
||||
|
||||
const isPrivate = !hasModifier(node, ts.NodeFlags.Export);
|
||||
const isPrivate = !ts.hasModifier(node, ts.ModifierFlags.Export);
|
||||
|
||||
let parameters: AST.Parameter[] = [];
|
||||
|
||||
@@ -397,7 +393,7 @@ class Walker {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPrivate = !hasModifier(node, ts.NodeFlags.Export);
|
||||
const isPrivate = !ts.hasModifier(node, ts.ModifierFlags.Export);
|
||||
|
||||
const interfase = this._scope.enter(new AST.Interface(node.name.text, node, jsDoc.description, generics, baseTypes, isPrivate));
|
||||
parent.members[interfase.name] = interfase;
|
||||
@@ -419,7 +415,7 @@ class Walker {
|
||||
return;
|
||||
}
|
||||
|
||||
const isPrivate = !hasModifier(node, ts.NodeFlags.Export);
|
||||
const isPrivate = !ts.hasModifier(node, ts.ModifierFlags.Export);
|
||||
|
||||
const type = this._typeChecker.getTypeAtLocation(node);
|
||||
|
||||
@@ -812,7 +808,7 @@ class Walker {
|
||||
}
|
||||
}
|
||||
|
||||
private _resolveTypeReference(unresolvedType: AST.UnresolvedType): AST.TypeReference | AST.IntrinsicTypeReference {
|
||||
private _resolveTypeReference(unresolvedType: AST.UnresolvedType): AST.TypeReference {
|
||||
let node: ts.Node = unresolvedType.symbol.declarations[0];
|
||||
while (node.kind !== ts.SyntaxKind.SourceFile) {
|
||||
node = node.parent;
|
||||
@@ -820,33 +816,28 @@ class Walker {
|
||||
|
||||
const sourceFile = node as ts.SourceFile;
|
||||
|
||||
if (sourceFile.fileName.substr(-"globals.d.ts".length) === "globals.d.ts") {
|
||||
return new AST.IntrinsicTypeReference(unresolvedType.symbol.name);
|
||||
const moduleName = this._moduleNameFromFileName(sourceFile.fileName);
|
||||
const module = this.modules[moduleName];
|
||||
|
||||
let result = module.members[unresolvedType.symbol.name];
|
||||
|
||||
if (result === undefined) {
|
||||
throw new Error(`Type ${ unresolvedType.symbol.name } could not be resolved.`);
|
||||
}
|
||||
else {
|
||||
const moduleName = this._moduleNameFromFileName(sourceFile.fileName);
|
||||
const module = this.modules[moduleName];
|
||||
|
||||
let result = module.members[unresolvedType.symbol.name];
|
||||
while (result instanceof AST.Reference) {
|
||||
result = this.modules[result.moduleName].members[result.name];
|
||||
}
|
||||
|
||||
if (result === undefined) {
|
||||
throw new Error(`Type ${unresolvedType.symbol.name} could not be resolved.`);
|
||||
const resultGenerics = unresolvedType.generics.map(generic => {
|
||||
if (generic instanceof AST.UnresolvedType) {
|
||||
return this._resolveTypeReference(generic);
|
||||
}
|
||||
|
||||
while (result instanceof AST.Reference) {
|
||||
result = this.modules[result.moduleName].members[result.name];
|
||||
}
|
||||
return generic;
|
||||
});
|
||||
|
||||
const resultGenerics = unresolvedType.generics.map(generic => {
|
||||
if (generic instanceof AST.UnresolvedType) {
|
||||
return this._resolveTypeReference(generic);
|
||||
}
|
||||
|
||||
return generic;
|
||||
});
|
||||
|
||||
return new AST.TypeReference(result, resultGenerics);
|
||||
}
|
||||
return new AST.TypeReference(result, resultGenerics);
|
||||
}
|
||||
|
||||
private _moduleNameFromFileName(fileName: string): string {
|
||||
@@ -872,7 +863,7 @@ export function walk(compiler: Compiler, root: string, rootNamespaceName: string
|
||||
if (
|
||||
path.basename(sourceFile.fileName) === "lib.es5.d.ts" ||
|
||||
path.basename(sourceFile.fileName) === "lib.dom.d.ts" ||
|
||||
sourceFile.fileName.substr(-"globals.d.ts".length) === "globals.d.ts"
|
||||
sourceFile.fileName.substr(-"references.d.ts".length) === "references.d.ts"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+1
-3
@@ -277,9 +277,7 @@ var Run = (function () {
|
||||
source_map: this._rootSourceMap,
|
||||
ascii_only: true,
|
||||
beautify: true,
|
||||
comments: function (node, comment) {
|
||||
return comment.value.indexOf("tslint") === -1;
|
||||
},
|
||||
comments: true,
|
||||
};
|
||||
|
||||
var stream = UglifyJS.OutputStream(output);
|
||||
|
||||
+2
-2
@@ -28,10 +28,10 @@
|
||||
"async": "1.x >=1.4",
|
||||
"async-build": "0.3.1",
|
||||
"intern": "3.x >=3.2.0",
|
||||
"npm": "4.x",
|
||||
"npm": "3.x",
|
||||
"pngjs": "3.x",
|
||||
"sax": "1.x",
|
||||
"typescript": "2.0.10",
|
||||
"typescript": "next",
|
||||
"uglify-js": "2.x >=2.4.24"
|
||||
},
|
||||
"private": true
|
||||
|
||||
Vendored
-163
@@ -1,163 +0,0 @@
|
||||
/**
|
||||
* libjass
|
||||
*
|
||||
* https://github.com/Arnavion/libjass
|
||||
*
|
||||
* Copyright 2013 Arnav Singh
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
interface Array<T> {
|
||||
filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
|
||||
}
|
||||
|
||||
interface WorkerGlobalScope {
|
||||
postMessage(message: any): void;
|
||||
addEventListener(type: string, listener: (message: any) => void, useCapture: boolean): void;
|
||||
}
|
||||
|
||||
interface FontFace {
|
||||
family: string;
|
||||
load(): Promise<FontFace>;
|
||||
}
|
||||
|
||||
interface FontFaceSet {
|
||||
add(fontFace: FontFace): FontFaceSet;
|
||||
forEach(callbackfn: (fontFace: FontFace, index: FontFace, set: FontFaceSet) => void, thisArg?: any): void;
|
||||
}
|
||||
|
||||
interface Map<K, V> {
|
||||
size: number;
|
||||
get(key: K): V | undefined;
|
||||
has(key: K): boolean;
|
||||
set(key: K, value: V): this;
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
forEach(callbackfn: (value: V, index: K, map: this) => void, thisArg?: any): void;
|
||||
}
|
||||
|
||||
interface Node {
|
||||
cloneNode(deep?: boolean): this;
|
||||
}
|
||||
|
||||
interface Promise<T> extends Thenable<T> {
|
||||
then<U>(onFulfilled: (value: T) => Thenable<U>, onRejected?: (reason: any) => U | Thenable<U>): Promise<U>;
|
||||
/* tslint:disable-next-line:unified-signatures */
|
||||
then<U>(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U | Thenable<U>): Promise<U>;
|
||||
catch(onRejected: (reason: any) => T | Thenable<T>): Promise<T>;
|
||||
}
|
||||
|
||||
interface ReadableStream {
|
||||
getReader(): ReadableStreamReader;
|
||||
}
|
||||
|
||||
interface ReadableStreamReader {
|
||||
read(): Promise<{ value: Uint8Array; done: boolean; }>;
|
||||
}
|
||||
|
||||
interface Set<T> {
|
||||
size: number;
|
||||
add(value: T): this;
|
||||
clear(): void;
|
||||
has(value: T): boolean;
|
||||
forEach(callbackfn: (value: T, index: T, set: this) => void, thisArg?: any): void;
|
||||
}
|
||||
|
||||
interface SVGFEComponentTransferElement {
|
||||
appendChild(newChild: SVGFEFuncAElement): SVGFEFuncAElement;
|
||||
appendChild(newChild: SVGFEFuncBElement): SVGFEFuncBElement;
|
||||
appendChild(newChild: SVGFEFuncGElement): SVGFEFuncGElement;
|
||||
appendChild(newChild: SVGFEFuncRElement): SVGFEFuncRElement;
|
||||
}
|
||||
|
||||
interface SVGFEMergeElement {
|
||||
appendChild(newChild: SVGFEMergeNodeElement): SVGFEMergeNodeElement;
|
||||
}
|
||||
|
||||
interface TextDecoder {
|
||||
decode(input: ArrayBuffer | ArrayBufferView, options: { stream: boolean }): string;
|
||||
}
|
||||
|
||||
interface Thenable<T> {
|
||||
then: ThenableThen<T>;
|
||||
}
|
||||
|
||||
type ThenableThen<T> = (this: Thenable<T>, resolve: ((resolution: T | Thenable<T>) => void) | undefined, reject: ((reason: any) => void) | undefined) => void;
|
||||
|
||||
/**
|
||||
* The interface implemented by a communication channel to the other side.
|
||||
*/
|
||||
interface WorkerCommunication {
|
||||
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
|
||||
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void;
|
||||
postMessage(message: any): void;
|
||||
}
|
||||
|
||||
declare const exports: any;
|
||||
|
||||
declare const global: (WorkerGlobalScope) & {
|
||||
FontFace?: {
|
||||
new (family: string, source: string): FontFace;
|
||||
};
|
||||
|
||||
Map?: {
|
||||
new <K, V>(iterable?: [K, V][]): Map<K, V>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Map<any, any> | { forEach: undefined };
|
||||
};
|
||||
|
||||
MutationObserver?: typeof MutationObserver;
|
||||
|
||||
Promise?: {
|
||||
new <T>(init: (resolve: (value: T | Thenable<T>) => void, reject: (reason: any) => void) => void): Promise<T>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Promise<any>;
|
||||
resolve<T>(value: T | Thenable<T>): Promise<T>;
|
||||
reject<T>(reason: any): Promise<T>;
|
||||
all<T>(values: (T | Thenable<T>)[]): Promise<T[]>;
|
||||
race<T>(values: (T | Thenable<T>)[]): Promise<T>;
|
||||
};
|
||||
|
||||
ReadableStream?: {
|
||||
prototype: ReadableStream | { getReader: undefined; };
|
||||
};
|
||||
|
||||
Set?: {
|
||||
new <T>(iterable?: T[]): Set<T>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Set<any> | { forEach: undefined };
|
||||
};
|
||||
|
||||
TextDecoder?: { new (encoding: string, options: { ignoreBOM: boolean }): TextDecoder };
|
||||
|
||||
WebkitMutationObserver?: typeof MutationObserver;
|
||||
|
||||
Worker?: typeof Worker,
|
||||
|
||||
WorkerGlobalScope?: {
|
||||
prototype: WorkerGlobalScope;
|
||||
new (): WorkerGlobalScope;
|
||||
};
|
||||
|
||||
document?: {
|
||||
currentScript?: HTMLScriptElement;
|
||||
fonts?: FontFaceSet;
|
||||
};
|
||||
|
||||
fetch?(url: string): Promise<{ body: ReadableStream; ok?: boolean; status?: number; }>;
|
||||
|
||||
process?: {
|
||||
nextTick?(callback: () => void): void;
|
||||
}
|
||||
};
|
||||
@@ -92,6 +92,8 @@ export function configure(newConfig: {
|
||||
}
|
||||
}
|
||||
|
||||
declare const exports: any;
|
||||
|
||||
// Getters below are to work around https://github.com/Microsoft/TypeScript/issues/6366
|
||||
|
||||
Object.defineProperties(exports, {
|
||||
|
||||
+207
-222
@@ -34,7 +34,6 @@ const rules = new Map<string, (parent: ParseNode) => ParseNode>();
|
||||
* @return {*} The value returned depends on the rule used.
|
||||
*/
|
||||
export function parse(input: string, rule: string): any {
|
||||
/* tslint:disable-next-line:no-use-before-declare */
|
||||
const { result } = new ParserRun(input, rule);
|
||||
|
||||
if (result === null || result.end !== input.length) {
|
||||
@@ -48,114 +47,6 @@ export function parse(input: string, rule: string): any {
|
||||
return result.value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a single parse node. It has a start and end position, and an optional value object.
|
||||
*
|
||||
* @param {ParseNode} parent The parent of this parse node.
|
||||
* @param {*=null} value If provided, it is assigned as the value of the node.
|
||||
*/
|
||||
class ParseNode {
|
||||
private _children: ParseNode[] = [];
|
||||
|
||||
private _start: number;
|
||||
private _end: number;
|
||||
private _value: any;
|
||||
|
||||
constructor(private _parent: ParseNode | null, value: any = null) {
|
||||
if (_parent !== null) {
|
||||
_parent.children.push(this);
|
||||
}
|
||||
|
||||
this._start = ((_parent !== null) ? _parent.end : 0);
|
||||
this._end = this._start;
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start position of this parse node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end position of this parse node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get end(): number {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ParseNode}
|
||||
*/
|
||||
get parent(): ParseNode | null {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {!Array.<!ParseNode>}
|
||||
*/
|
||||
get children(): ParseNode[] {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional object associated with this parse node.
|
||||
*
|
||||
* @type {*}
|
||||
*/
|
||||
get value(): any {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional object associated with this parse node.
|
||||
*
|
||||
* If the value is a string, then the end property is updated to be the length of the string.
|
||||
*
|
||||
* @type {*}
|
||||
*/
|
||||
set value(newValue: any) {
|
||||
this._value = newValue;
|
||||
|
||||
if (this._value !== null && this._value.constructor === String && this._children.length === 0) {
|
||||
this._setEnd(this._start + (this._value as string).length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last child of this node and updates the end position to be end position of the new last child.
|
||||
*/
|
||||
pop(): void {
|
||||
this._children.splice(this._children.length - 1, 1);
|
||||
|
||||
if (this._children.length > 0) {
|
||||
this._setEnd(this._children[this._children.length - 1].end);
|
||||
}
|
||||
else {
|
||||
this._setEnd(this.start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the end property of this node and its parent recursively to the root node.
|
||||
*
|
||||
* @param {number} newEnd
|
||||
*/
|
||||
private _setEnd(newEnd: number): void {
|
||||
this._end = newEnd;
|
||||
|
||||
if (this._parent !== null && this._parent.end !== this._end) {
|
||||
this._parent._setEnd(this._end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a single run of the parser.
|
||||
*
|
||||
@@ -201,7 +92,7 @@ class ParserRun {
|
||||
}
|
||||
|
||||
else {
|
||||
const whiteSpaceOrTextNode = this.parse_newline(current) || this.parse_soft_newline(current) || this.parse_hardspace(current) || this.parse_text(current);
|
||||
const whiteSpaceOrTextNode = this.parse_newline(current) || this.parse_hardspace(current) || this.parse_text(current);
|
||||
|
||||
if (whiteSpaceOrTextNode.value instanceof parts.Text && current.value[current.value.length - 1] instanceof parts.Text) {
|
||||
// Merge consecutive text parts into one part
|
||||
@@ -315,16 +206,22 @@ class ParserRun {
|
||||
childNode = this.parse_comment(current);
|
||||
}
|
||||
|
||||
if (childNode.value instanceof parts.Comment && current.value[current.value.length - 1] instanceof parts.Comment) {
|
||||
// Merge consecutive comment parts into one part
|
||||
current.value[current.value.length - 1] =
|
||||
new parts.Comment(
|
||||
(current.value[current.value.length - 1] as parts.Comment).value +
|
||||
(childNode.value as parts.Comment).value,
|
||||
);
|
||||
if (childNode !== null) {
|
||||
if (childNode.value instanceof parts.Comment && current.value[current.value.length - 1] instanceof parts.Comment) {
|
||||
// Merge consecutive comment parts into one part
|
||||
current.value[current.value.length - 1] =
|
||||
new parts.Comment(
|
||||
(current.value[current.value.length - 1] as parts.Comment).value +
|
||||
(childNode.value as parts.Comment).value
|
||||
);
|
||||
}
|
||||
else {
|
||||
current.value.push(childNode.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
current.value.push(childNode.value);
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -353,23 +250,6 @@ class ParserRun {
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_soft_newline(parent: ParseNode): ParseNode | null {
|
||||
const current = new ParseNode(parent);
|
||||
|
||||
if (this.read(current, "\\n") === null) {
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
|
||||
current.value = new parts.SoftNewLine();
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
@@ -507,8 +387,8 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_alpha(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_alpha(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -579,32 +459,32 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_be(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_be(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_blur(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_blur(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_bord(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_bord(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_c(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_c(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -756,7 +636,7 @@ class ParserRun {
|
||||
current.value =
|
||||
new parts.ComplexFade(
|
||||
1 - a1Node.value / 255, 1 - a2Node.value / 255, 1 - a3Node.value / 255,
|
||||
t1Node.value / 1000, t2Node.value / 1000, t3Node.value / 1000, t4Node.value / 1000,
|
||||
t1Node.value / 1000, t2Node.value / 1000, t3Node.value / 1000, t4Node.value / 1000
|
||||
);
|
||||
|
||||
return current;
|
||||
@@ -766,16 +646,16 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fax(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fax(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fay(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fay(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -810,40 +690,40 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fr(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fr(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_frx(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_frx(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fry(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fry(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_frz(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_frz(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fs(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fs(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -946,16 +826,16 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_fsp(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_fsp(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_i(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_i(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1147,7 +1027,7 @@ class ParserRun {
|
||||
|
||||
current.value = new parts.Move(
|
||||
x1Node.value, y1Node.value, x2Node.value, y2Node.value,
|
||||
(t1Node !== null) ? (t1Node.value / 1000) : null, (t2Node !== null) ? (t2Node.value / 1000) : null,
|
||||
(t1Node !== null) ? (t1Node.value / 1000) : null, (t2Node !== null) ? (t2Node.value / 1000) : null
|
||||
);
|
||||
|
||||
return current;
|
||||
@@ -1201,16 +1081,16 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_p(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_p(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_pbo(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_pbo(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1315,16 +1195,16 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_s(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_s(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_shad(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_shad(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1438,16 +1318,22 @@ class ParserRun {
|
||||
childNode = this.parse_comment(current);
|
||||
}
|
||||
|
||||
if (childNode.value instanceof parts.Comment && transformTags[transformTags.length - 1] instanceof parts.Comment) {
|
||||
// Merge consecutive comment parts into one part
|
||||
transformTags[transformTags.length - 1] =
|
||||
new parts.Comment(
|
||||
(transformTags[transformTags.length - 1] as parts.Comment).value +
|
||||
(childNode.value as parts.Comment).value,
|
||||
);
|
||||
if (childNode !== null) {
|
||||
if (childNode.value instanceof parts.Comment && transformTags[transformTags.length - 1] instanceof parts.Comment) {
|
||||
// Merge consecutive comment parts into one part
|
||||
transformTags[transformTags.length - 1] =
|
||||
new parts.Comment(
|
||||
(transformTags[transformTags.length - 1] as parts.Comment).value +
|
||||
(childNode.value as parts.Comment).value
|
||||
);
|
||||
}
|
||||
else {
|
||||
transformTags.push(childNode.value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
transformTags.push(childNode.value);
|
||||
parent.pop();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1458,7 +1344,7 @@ class ParserRun {
|
||||
(startNode !== null) ? (startNode.value / 1000) : null,
|
||||
(endNode !== null) ? (endNode.value / 1000) : null,
|
||||
(accelNode !== null) ? (accelNode.value / 1000) : null,
|
||||
transformTags,
|
||||
transformTags
|
||||
);
|
||||
|
||||
return current;
|
||||
@@ -1468,104 +1354,104 @@ class ParserRun {
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_u(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_u(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_xbord(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_xbord(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_xshad(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_xshad(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_ybord(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_ybord(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_yshad(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_yshad(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_1a(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_1a(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_1c(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_1c(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_2a(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_2a(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_2c(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_2c(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_3a(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_3a(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_3c(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_3c(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_4a(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_4a(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!ParseNode} parent
|
||||
* @return {ParseNode}
|
||||
*/
|
||||
parse_tag_4c(_parent: ParseNode): ParseNode | null {
|
||||
throw new Error("unreachable");
|
||||
parse_tag_4c(parent: ParseNode): ParseNode | null {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1780,7 +1666,7 @@ class ParserRun {
|
||||
}
|
||||
}
|
||||
|
||||
current.value = parseFloat((characteristicNode.value as string) + ((mantissaNode !== null) ? ("." + (mantissaNode.value as string)) : ""));
|
||||
current.value = parseFloat(characteristicNode.value + ((mantissaNode !== null) ? ("." + mantissaNode.value) : ""));
|
||||
|
||||
return current;
|
||||
}
|
||||
@@ -1819,16 +1705,12 @@ class ParserRun {
|
||||
|
||||
const value = valueNode.value;
|
||||
|
||||
/* tslint:disable:no-bitwise */
|
||||
|
||||
current.value = new parts.Color(
|
||||
value & 0xFF,
|
||||
(value >> 8) & 0xFF,
|
||||
(value >> 16) & 0xFF,
|
||||
(value >> 16) & 0xFF
|
||||
);
|
||||
|
||||
/* tslint:enable:no-bitwise */
|
||||
|
||||
while (this.read(current, "&") !== null || this.read(current, "H") !== null) { }
|
||||
|
||||
return current;
|
||||
@@ -1851,7 +1733,6 @@ class ParserRun {
|
||||
|
||||
const value = valueNode.value;
|
||||
|
||||
/* tslint:disable-next-line:no-bitwise */
|
||||
current.value = 1 - (value & 0xFF) / 0xFF;
|
||||
|
||||
while (this.read(current, "&") !== null || this.read(current, "H") !== null) { }
|
||||
@@ -1874,17 +1755,13 @@ class ParserRun {
|
||||
|
||||
const value = valueNode.value;
|
||||
|
||||
/* tslint:disable:no-bitwise */
|
||||
|
||||
current.value = new parts.Color(
|
||||
value & 0xFF,
|
||||
(value >> 8) & 0xFF,
|
||||
(value >> 16) & 0xFF,
|
||||
1 - ((value >> 24) & 0xFF) / 0xFF,
|
||||
1 - ((value >> 24) & 0xFF) / 0xFF
|
||||
);
|
||||
|
||||
/* tslint:enable:no-bitwise */
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
@@ -2019,7 +1896,7 @@ function makeTagParserFunction(
|
||||
tagName: string,
|
||||
tagConstructor: { new (value: any): parts.Part },
|
||||
valueParser: (current: ParseNode) => ParseNode | null,
|
||||
required: boolean,
|
||||
required: boolean
|
||||
): void {
|
||||
(ParserRun.prototype as any)[`parse_tag_${ tagName }`] = function (this: ParserRun, parent: ParseNode): ParseNode | null {
|
||||
const current = new ParseNode(parent);
|
||||
@@ -2084,11 +1961,119 @@ for (const key of Object.keys(ParserRun.prototype)) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class represents a single parse node. It has a start and end position, and an optional value object.
|
||||
*
|
||||
* @param {ParseNode} parent The parent of this parse node.
|
||||
* @param {*=null} value If provided, it is assigned as the value of the node.
|
||||
*/
|
||||
class ParseNode {
|
||||
private _children: ParseNode[] = [];
|
||||
|
||||
private _start: number;
|
||||
private _end: number;
|
||||
private _value: any;
|
||||
|
||||
constructor(private _parent: ParseNode | null, value: any = null) {
|
||||
if (_parent !== null) {
|
||||
_parent.children.push(this);
|
||||
}
|
||||
|
||||
this._start = ((_parent !== null) ? _parent.end : 0);
|
||||
this._end = this._start;
|
||||
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The start position of this parse node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get start(): number {
|
||||
return this._start;
|
||||
}
|
||||
|
||||
/**
|
||||
* The end position of this parse node.
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get end(): number {
|
||||
return this._end;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {ParseNode}
|
||||
*/
|
||||
get parent(): ParseNode | null {
|
||||
return this._parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {!Array.<!ParseNode>}
|
||||
*/
|
||||
get children(): ParseNode[] {
|
||||
return this._children;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional object associated with this parse node.
|
||||
*
|
||||
* @type {*}
|
||||
*/
|
||||
get value(): any {
|
||||
return this._value;
|
||||
}
|
||||
|
||||
/**
|
||||
* An optional object associated with this parse node.
|
||||
*
|
||||
* If the value is a string, then the end property is updated to be the length of the string.
|
||||
*
|
||||
* @type {*}
|
||||
*/
|
||||
set value(newValue: any) {
|
||||
this._value = newValue;
|
||||
|
||||
if (this._value !== null && this._value.constructor === String && this._children.length === 0) {
|
||||
this._setEnd(this._start + this._value.length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the last child of this node and updates the end position to be end position of the new last child.
|
||||
*/
|
||||
pop(): void {
|
||||
this._children.splice(this._children.length - 1, 1);
|
||||
|
||||
if (this._children.length > 0) {
|
||||
this._setEnd(this._children[this._children.length - 1].end);
|
||||
}
|
||||
else {
|
||||
this._setEnd(this.start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the end property of this node and its parent recursively to the root node.
|
||||
*
|
||||
* @param {number} newEnd
|
||||
*/
|
||||
private _setEnd(newEnd: number): void {
|
||||
this._end = newEnd;
|
||||
|
||||
if (this._parent !== null && this._parent.end !== this._end) {
|
||||
this._parent._setEnd(this._end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import { Promise } from "../utility/promise";
|
||||
|
||||
import { WorkerCommands } from "../webworker/commands";
|
||||
import { registerWorkerCommand } from "../webworker/misc";
|
||||
|
||||
registerWorkerCommand(WorkerCommands.Parse, parameters => new Promise<any>(resolve => {
|
||||
registerWorkerCommand(WorkerCommands.Parse, parameters => new Promise(resolve => {
|
||||
resolve(parse(parameters.input, parameters.rule));
|
||||
}));
|
||||
|
||||
@@ -21,13 +21,13 @@
|
||||
import { debugMode } from "../settings";
|
||||
|
||||
import { ASS } from "../types/ass";
|
||||
import { Attachment, AttachmentType } from "../types/attachment";
|
||||
import { Dialogue } from "../types/dialogue";
|
||||
import { Style } from "../types/style";
|
||||
import { Dialogue } from "../types/dialogue";
|
||||
import { Attachment, AttachmentType } from "../types/attachment";
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
|
||||
import { DeferredPromise } from "../utility/promise";
|
||||
import { Promise, DeferredPromise } from "../utility/promise";
|
||||
|
||||
import { parseLineIntoProperty } from "./misc";
|
||||
import { Stream } from "./streams";
|
||||
@@ -57,7 +57,6 @@ export class StreamParser {
|
||||
private _currentAttachment: Attachment | null = null;
|
||||
|
||||
constructor(private _stream: Stream) {
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
this._stream.nextLine().then(line => this._onNextLine(line), reason => {
|
||||
this._minimalDeferred.reject(reason);
|
||||
this._deferred.reject(reason);
|
||||
@@ -102,7 +101,6 @@ export class StreamParser {
|
||||
|
||||
if (value === Section.EOF) {
|
||||
const scriptProperties = this._ass.properties;
|
||||
/* tslint:disable-next-line:strict-type-predicates */
|
||||
if (scriptProperties.resolutionX === undefined || scriptProperties.resolutionY === undefined) {
|
||||
// Malformed script.
|
||||
this._minimalDeferred.reject("Malformed ASS script.");
|
||||
@@ -274,7 +272,6 @@ export class StreamParser {
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
this._stream.nextLine().then(line => this._onNextLine(line), reason => {
|
||||
this._minimalDeferred.reject(reason);
|
||||
this._deferred.reject(reason);
|
||||
@@ -299,7 +296,6 @@ export class SrtStreamParser {
|
||||
private _currentDialogueText: string | null = null;
|
||||
|
||||
constructor(private _stream: Stream) {
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
this._stream.nextLine().then(line => this._onNextLine(line), reason => {
|
||||
this._deferred.reject(reason);
|
||||
});
|
||||
@@ -383,7 +379,7 @@ export class SrtStreamParser {
|
||||
.replace(/<\/u>/g, "{\\u0}").replace(/\{\/u\}/g, "{\\u0}")
|
||||
.replace(
|
||||
/<font color="#([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})">/g,
|
||||
(/* ujs:unreferenced */ _substring: string, red: string, green: string, blue: string) => `{\c&H${ blue }${ green }${ red }&}`,
|
||||
(/* ujs:unreferenced */ substring: string, red: string, green: string, blue: string) => `{\c&H${ blue }${ green }${ red }&}`
|
||||
).replace(/<\/font>/g, "{\\c}");
|
||||
|
||||
if (this._currentDialogueText !== null) {
|
||||
@@ -395,7 +391,6 @@ export class SrtStreamParser {
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
this._stream.nextLine().then(line => this._onNextLine(line), reason => {
|
||||
this._deferred.reject(reason);
|
||||
});
|
||||
|
||||
+44
-14
@@ -18,7 +18,45 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { DeferredPromise, Promise } from "../utility/promise";
|
||||
import { Promise, DeferredPromise } from "../utility/promise";
|
||||
|
||||
export interface ReadableStream {
|
||||
/**
|
||||
* @return {!ReadableStreamReader}
|
||||
*/
|
||||
getReader(): ReadableStreamReader;
|
||||
}
|
||||
|
||||
export interface ReadableStreamReader {
|
||||
/**
|
||||
* @return {!Promise.<{ value?: Uint8Array, done: boolean }>}
|
||||
*/
|
||||
read(): Promise<{ value: Uint8Array; done: boolean; }>;
|
||||
}
|
||||
|
||||
export interface TextDecoder {
|
||||
/**
|
||||
* @param {!ArrayBuffer|!ArrayBufferView} input
|
||||
* @param {{ stream: boolean }} options
|
||||
* @return {string}
|
||||
*/
|
||||
decode(input: ArrayBuffer | ArrayBufferView, options: { stream: boolean }): string;
|
||||
}
|
||||
export interface TextDecoderConstructor {
|
||||
new (encoding: string, options: { ignoreBOM: boolean }): TextDecoder;
|
||||
|
||||
/**
|
||||
* @type {!TextDecoder}
|
||||
*/
|
||||
prototype: TextDecoder;
|
||||
}
|
||||
|
||||
declare const global: {
|
||||
/**
|
||||
* @type {!TextDecoderConstructor}
|
||||
*/
|
||||
TextDecoder?: TextDecoderConstructor;
|
||||
};
|
||||
|
||||
/**
|
||||
* An interface for a stream.
|
||||
@@ -157,8 +195,12 @@ export class XhrStream implements Stream {
|
||||
}
|
||||
|
||||
else if (this._xhr.readyState === XMLHttpRequest.DONE) {
|
||||
if (this._failedError !== null) {
|
||||
this._pendingDeferred!.reject(this._failedError);
|
||||
}
|
||||
|
||||
// No more data. This is the last line.
|
||||
if (this._readTill < response.length) {
|
||||
else if (this._readTill < response.length) {
|
||||
this._pendingDeferred!.resolve(response.substr(this._readTill));
|
||||
this._readTill = response.length;
|
||||
}
|
||||
@@ -178,17 +220,6 @@ export class XhrStream implements Stream {
|
||||
* @param {string} encoding
|
||||
*/
|
||||
export class BrowserReadableStream implements Stream {
|
||||
/**
|
||||
* @return {boolean} Whether BrowserReadableStream is supported in this environment.
|
||||
*/
|
||||
static isSupported(): boolean {
|
||||
return (
|
||||
global.ReadableStream !== undefined &&
|
||||
typeof global.ReadableStream.prototype.getReader === "function" &&
|
||||
typeof global.TextDecoder === "function"
|
||||
);
|
||||
}
|
||||
|
||||
private _reader: ReadableStreamReader;
|
||||
private _decoder: TextDecoder;
|
||||
private _buffer: string = "";
|
||||
@@ -225,7 +256,6 @@ export class BrowserReadableStream implements Stream {
|
||||
}
|
||||
|
||||
else {
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
this._reader.read().then(next => {
|
||||
const { value, done } = next;
|
||||
|
||||
|
||||
+14
-18
@@ -37,22 +37,19 @@ const fieldDecorators = new Map<DataType, (proto: any, field: string) => void>()
|
||||
|
||||
@struct
|
||||
class OffsetTable {
|
||||
/** @type {function(!{ dataView: DataView, position: number }): OffsetTable} */
|
||||
static read: (reader: DataReader) => OffsetTable;
|
||||
|
||||
/** @type {number} */ @field(DataType.Uint16) majorVersion: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) minorVersion: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) numTables: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) searchRange: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) entrySelector: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) rangeShift: number;
|
||||
|
||||
/** @type {function(!{ dataView: DataView, position: number }): OffsetTable} */
|
||||
static read: (reader: DataReader) => OffsetTable;
|
||||
}
|
||||
|
||||
@struct
|
||||
class TableRecord {
|
||||
/** @type {function(!{ dataView: DataView, position: number }): TableRecord} */
|
||||
static read: (reader: DataReader) => TableRecord;
|
||||
|
||||
/** @type {string} */ @field(DataType.Char) c1: string;
|
||||
/** @type {string} */ @field(DataType.Char) c2: string;
|
||||
/** @type {string} */ @field(DataType.Char) c3: string;
|
||||
@@ -60,29 +57,32 @@ class TableRecord {
|
||||
/** @type {number} */ @field(DataType.Uint32) checksum: number;
|
||||
/** @type {number} */ @field(DataType.Uint32) offset: number;
|
||||
/** @type {number} */ @field(DataType.Uint32) length: number;
|
||||
|
||||
/** @type {function(!{ dataView: DataView, position: number }): TableRecord} */
|
||||
static read: (reader: DataReader) => TableRecord;
|
||||
}
|
||||
|
||||
@struct
|
||||
class NameTableHeader {
|
||||
/** @type {function(!{ dataView: DataView, position: number }): NameTableHeader} */
|
||||
static read: (reader: DataReader) => NameTableHeader;
|
||||
|
||||
/** @type {number} */ @field(DataType.Uint16) formatSelector: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) count: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) stringOffset: number;
|
||||
|
||||
/** @type {function(!{ dataView: DataView, position: number }): NameTableHeader} */
|
||||
static read: (reader: DataReader) => NameTableHeader;
|
||||
}
|
||||
|
||||
@struct
|
||||
class NameRecord {
|
||||
/** @type {function(!{ dataView: DataView, position: number }): NameRecord} */
|
||||
static read: (reader: DataReader) => NameRecord;
|
||||
|
||||
/** @type {number} */ @field(DataType.Uint16) platformId: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) encodingId: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) languageId: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) nameId: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) length: number;
|
||||
/** @type {number} */ @field(DataType.Uint16) offset: number;
|
||||
|
||||
/** @type {function(!{ dataView: DataView, position: number }): NameRecord} */
|
||||
static read: (reader: DataReader) => NameRecord;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -133,28 +133,24 @@ export function getTtfNames(attachment: Attachment): Set<string> {
|
||||
case 1: {
|
||||
let name = "";
|
||||
|
||||
/* tslint:disable-next-line:prefer-for-of */
|
||||
for (let j = 0; j < nameBytes.length; j++) {
|
||||
name += String.fromCharCode(nameBytes[j]);
|
||||
}
|
||||
|
||||
result.add(name);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3: {
|
||||
let name = "";
|
||||
|
||||
for (let j = 0; j < nameBytes.length; j += 2) {
|
||||
/* tslint:disable-next-line:no-bitwise */
|
||||
name += String.fromCharCode((nameBytes[j] << 8) + nameBytes[j + 1]);
|
||||
}
|
||||
|
||||
result.add(name);
|
||||
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
+71
-66
@@ -77,7 +77,11 @@ export class Color {
|
||||
* @return {!libjass.parts.Color} Returns a new Color instance with the same color but the provided alpha.
|
||||
*/
|
||||
withAlpha(value: number): Color {
|
||||
return new Color(this._red, this._green, this._blue, value);
|
||||
if (value !== null) {
|
||||
return new Color(this._red, this._green, this._blue, value);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -99,7 +103,7 @@ export class Color {
|
||||
this._red + progression * (final.red - this._red),
|
||||
this._green + progression * (final.green - this._green),
|
||||
this._blue + progression * (final.blue - this._blue),
|
||||
this._alpha + progression * (final.alpha - this._alpha),
|
||||
this._alpha + progression * (final.alpha - this._alpha)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -158,26 +162,20 @@ export class Text {
|
||||
export class NewLine {
|
||||
}
|
||||
|
||||
/**
|
||||
* A soft newline character \n.
|
||||
*/
|
||||
export class SoftNewLine {
|
||||
}
|
||||
|
||||
/**
|
||||
* An italic tag {\i}
|
||||
*
|
||||
* @param {?boolean} value {\i1} -> true, {\i0} -> false, {\i} -> null
|
||||
*/
|
||||
export class Italic {
|
||||
constructor(private _value: boolean | null) { }
|
||||
constructor(private _value: boolean) { }
|
||||
|
||||
/**
|
||||
* The value of this italic tag.
|
||||
*
|
||||
* @type {?boolean}
|
||||
*/
|
||||
get value(): boolean | null {
|
||||
get value(): boolean {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -206,14 +204,14 @@ export class Bold {
|
||||
* @param {?boolean} value {\u1} -> true, {\u0} -> false, {\u} -> null
|
||||
*/
|
||||
export class Underline {
|
||||
constructor(private _value: boolean | null) { }
|
||||
constructor(private _value: boolean) { }
|
||||
|
||||
/**
|
||||
* The value of this underline tag.
|
||||
*
|
||||
* @type {?boolean}
|
||||
*/
|
||||
get value(): boolean | null {
|
||||
get value(): boolean {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -224,14 +222,14 @@ export class Underline {
|
||||
* @param {?boolean} value {\s1} -> true, {\s0} -> false, {\s} -> null
|
||||
*/
|
||||
export class StrikeThrough {
|
||||
constructor(private _value: boolean | null) { }
|
||||
constructor(private _value: boolean) { }
|
||||
|
||||
/**
|
||||
* The value of this strike-through tag.
|
||||
*
|
||||
* @type {?boolean}
|
||||
*/
|
||||
get value(): boolean | null {
|
||||
get value(): boolean {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -242,14 +240,14 @@ export class StrikeThrough {
|
||||
* @param {?number} value {\bord###} -> width (number), {\bord} -> null
|
||||
*/
|
||||
export class Border {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this border tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -260,14 +258,14 @@ export class Border {
|
||||
* @param {?number} value {\xbord###} -> width (number), {\xbord} -> null
|
||||
*/
|
||||
export class BorderX {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this horizontal border tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -278,14 +276,14 @@ export class BorderX {
|
||||
* @param {?number} value {\ybord###} -> height (number), {\ybord} -> null
|
||||
*/
|
||||
export class BorderY {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this vertical border tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -296,14 +294,14 @@ export class BorderY {
|
||||
* @param {?number} value {\shad###} -> depth (number), {\shad} -> null
|
||||
*/
|
||||
export class Shadow {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this shadow tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -314,14 +312,14 @@ export class Shadow {
|
||||
* @param {?number} value {\xshad###} -> depth (number), {\xshad} -> null
|
||||
*/
|
||||
export class ShadowX {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this horizontal shadow tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -332,14 +330,14 @@ export class ShadowX {
|
||||
* @param {?number} value {\yshad###} -> depth (number), {\yshad} -> null
|
||||
*/
|
||||
export class ShadowY {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this vertical shadow tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -350,14 +348,14 @@ export class ShadowY {
|
||||
* @param {?number} value {\be###} -> strength (number), {\be} -> null
|
||||
*/
|
||||
export class Blur {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this blur tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -368,14 +366,14 @@ export class Blur {
|
||||
* @param {?number} value {\blur###} -> strength (number), {\blur} -> null
|
||||
*/
|
||||
export class GaussianBlur {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this Gaussian blur tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -404,14 +402,14 @@ export class FontName {
|
||||
* @param {?number} value {\fs###} -> size (number), {\fs} -> null
|
||||
*/
|
||||
export class FontSize {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this font size tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -494,14 +492,14 @@ export class FontScaleY {
|
||||
* @param {?number} value {\fsp###} -> spacing (number), {\fsp} -> null
|
||||
*/
|
||||
export class LetterSpacing {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this letter-spacing tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -512,14 +510,14 @@ export class LetterSpacing {
|
||||
* @param {?number} value {\frx###} -> angle (number), {\frx} -> null
|
||||
*/
|
||||
export class RotateX {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this X-axis rotation tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -530,14 +528,14 @@ export class RotateX {
|
||||
* @param {?number} value {\fry###} -> angle (number), {\fry} -> null
|
||||
*/
|
||||
export class RotateY {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this Y-axis rotation tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -548,14 +546,14 @@ export class RotateY {
|
||||
* @param {?number} value {\frz###} -> angle (number), {\frz} -> null
|
||||
*/
|
||||
export class RotateZ {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this Z-axis rotation tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -566,14 +564,14 @@ export class RotateZ {
|
||||
* @param {?number} value {\fax###} -> angle (number), {\fax} -> null
|
||||
*/
|
||||
export class SkewX {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this X-axis shearing tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -584,14 +582,14 @@ export class SkewX {
|
||||
* @param {?number} value {\fay###} -> angle (number), {\fay} -> null
|
||||
*/
|
||||
export class SkewY {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this Y-axis shearing tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -602,14 +600,14 @@ export class SkewY {
|
||||
* @param {libjass.parts.Color} value {\1c###} -> color (Color), {\1c} -> null
|
||||
*/
|
||||
export class PrimaryColor {
|
||||
constructor(private _value: Color | null) { }
|
||||
constructor(private _value: Color) { }
|
||||
|
||||
/**
|
||||
* The value of this primary color tag.
|
||||
*
|
||||
* @type {libjass.parts.Color}
|
||||
*/
|
||||
get value(): Color | null {
|
||||
get value(): Color {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -620,14 +618,14 @@ export class PrimaryColor {
|
||||
* @param {libjass.parts.Color} value {\2c###} -> color (Color), {\2c} -> null
|
||||
*/
|
||||
export class SecondaryColor {
|
||||
constructor(private _value: Color | null) { }
|
||||
constructor(private _value: Color) { }
|
||||
|
||||
/**
|
||||
* The value of this secondary color tag.
|
||||
*
|
||||
* @type {libjass.parts.Color}
|
||||
*/
|
||||
get value(): Color | null {
|
||||
get value(): Color {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -638,14 +636,14 @@ export class SecondaryColor {
|
||||
* @param {libjass.parts.Color} value {\3c###} -> color (Color), {\3c} -> null
|
||||
*/
|
||||
export class OutlineColor {
|
||||
constructor(private _value: Color | null) { }
|
||||
constructor(private _value: Color) { }
|
||||
|
||||
/**
|
||||
* The value of this outline color tag.
|
||||
*
|
||||
* @type {libjass.parts.Color}
|
||||
*/
|
||||
get value(): Color | null {
|
||||
get value(): Color {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -656,14 +654,14 @@ export class OutlineColor {
|
||||
* @param {libjass.parts.Color} value {\4c###} -> color (Color), {\4c} -> null
|
||||
*/
|
||||
export class ShadowColor {
|
||||
constructor(private _value: Color | null) { }
|
||||
constructor(private _value: Color) { }
|
||||
|
||||
/**
|
||||
* The value of this shadow color tag.
|
||||
*
|
||||
* @type {libjass.parts.Color}
|
||||
*/
|
||||
get value(): Color | null {
|
||||
get value(): Color {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -674,14 +672,14 @@ export class ShadowColor {
|
||||
* @param {?number} value {\alpha###} -> alpha (number), {\alpha} -> null
|
||||
*/
|
||||
export class Alpha {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this alpha tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -692,14 +690,14 @@ export class Alpha {
|
||||
* @param {?number} value {\1a###} -> alpha (number), {\1a} -> null
|
||||
*/
|
||||
export class PrimaryAlpha {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this primary alpha tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -710,14 +708,14 @@ export class PrimaryAlpha {
|
||||
* @param {?number} value {\2a###} -> alpha (number), {\2a} -> null
|
||||
*/
|
||||
export class SecondaryAlpha {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this secondary alpha tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -728,14 +726,14 @@ export class SecondaryAlpha {
|
||||
* @param {?number} value {\3a###} -> alpha (number), {\3a} -> null
|
||||
*/
|
||||
export class OutlineAlpha {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this outline alpha tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -746,14 +744,14 @@ export class OutlineAlpha {
|
||||
* @param {?number} value {\4a###} -> alpha (number), {\4a} -> null
|
||||
*/
|
||||
export class ShadowAlpha {
|
||||
constructor(private _value: number | null) { }
|
||||
constructor(private _value: number) { }
|
||||
|
||||
/**
|
||||
* The value of this shadow alpha tag.
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
get value(): number | null {
|
||||
get value(): number {
|
||||
return this._value;
|
||||
}
|
||||
}
|
||||
@@ -1032,7 +1030,7 @@ export class Fade {
|
||||
export class ComplexFade {
|
||||
constructor(
|
||||
private _a1: number, private _a2: number, private _a3: number,
|
||||
private _t1: number, private _t2: number, private _t3: number, private _t4: number,
|
||||
private _t1: number, private _t2: number, private _t3: number, private _t4: number
|
||||
) { }
|
||||
|
||||
/**
|
||||
@@ -1297,18 +1295,25 @@ export class DrawingInstructions {
|
||||
}
|
||||
}
|
||||
|
||||
const addToString = function (ctor: Function, ctorName: string): void {
|
||||
const addToString = function (ctor: Function, ctorName: string) {
|
||||
if (!ctor.prototype.hasOwnProperty("toString")) {
|
||||
const propertyNames = Object.getOwnPropertyNames(ctor.prototype).filter(property => property !== "constructor");
|
||||
|
||||
ctor.prototype.toString = function (this: any): string {
|
||||
return `${ ctorName } { ${ propertyNames.map(name => `${ name }: ${ this[name] }`).join(", ") }${ (propertyNames.length > 0) ? " " : "" }}`;
|
||||
ctor.prototype.toString = function (this: any) {
|
||||
return (
|
||||
ctorName + " { " +
|
||||
propertyNames.map(name => `${ name }: ${ this[name] }`).join(", ") +
|
||||
((propertyNames.length > 0) ? " " : "") +
|
||||
"}"
|
||||
);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
import { registerClass } from "../serialization";
|
||||
|
||||
declare const exports: any;
|
||||
|
||||
for (const key of Object.keys(exports)) {
|
||||
const value: any = exports[key];
|
||||
if (value instanceof Function) {
|
||||
|
||||
@@ -44,7 +44,7 @@ export class AutoClock implements Clock {
|
||||
private _nextAnimationFrameRequestId: number | null = null;
|
||||
|
||||
private _lastKnownExternalTime: number | null = null;
|
||||
private _lastKnownExternalTimeObtainedAt: number = 0;
|
||||
private _lastKnownExternalTimeObtainedAt: number | null = null;
|
||||
|
||||
constructor(private _getCurrentTime: () => number, private _autoPauseAfter: number) { }
|
||||
|
||||
@@ -193,7 +193,7 @@ export class AutoClock implements Clock {
|
||||
*/
|
||||
addEventListener(type: ClockEvent, listener: Function): void {
|
||||
this._manualClock.addEventListener(type, listener);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {number} timeStamp
|
||||
@@ -213,7 +213,7 @@ export class AutoClock implements Clock {
|
||||
if (!this._manualClock.paused) {
|
||||
if (this._lastKnownExternalTime !== null && currentExternalTime === this._lastKnownExternalTime) {
|
||||
if (timeStamp - this._lastKnownExternalTimeObtainedAt > this._autoPauseAfter) {
|
||||
this._lastKnownExternalTimeObtainedAt = 0;
|
||||
this._lastKnownExternalTimeObtainedAt = null;
|
||||
this._manualClock.seek(currentExternalTime);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
|
||||
/**
|
||||
* A mixin class that represents an event source.
|
||||
*/
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
import { mixin } from "../../utility/mixin";
|
||||
import { Map } from "../../utility/map";
|
||||
|
||||
import { Clock, ClockEvent, EventSource } from "./base";
|
||||
|
||||
@@ -226,8 +226,6 @@ export class ManualClock implements Clock, EventSource<ClockEvent> {
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable:member-ordering */
|
||||
|
||||
// EventSource members
|
||||
|
||||
/**
|
||||
@@ -244,7 +242,5 @@ export class ManualClock implements Clock, EventSource<ClockEvent> {
|
||||
* @type {function(number, Array.<*>)}
|
||||
*/
|
||||
_dispatchEvent: (type: ClockEvent, args: Object[]) => void;
|
||||
|
||||
/* tslint:enable:member-ordering */
|
||||
}
|
||||
mixin(ManualClock, [EventSource]);
|
||||
|
||||
@@ -35,7 +35,7 @@ export class DefaultRenderer extends WebRenderer {
|
||||
constructor(private _video: HTMLVideoElement, ass: ASS, settings?: RendererSettings) {
|
||||
super(ass, new VideoClock(_video), document.createElement("div"), settings);
|
||||
|
||||
this._video.parentElement!.replaceChild(this.libjassSubsWrapper, this._video);
|
||||
this._video.parentElement.replaceChild(this.libjassSubsWrapper, this._video);
|
||||
this.libjassSubsWrapper.insertBefore(this._video, this.libjassSubsWrapper.firstElementChild);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,15 +18,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Clock, ClockEvent } from "./clocks/base";
|
||||
|
||||
import { RendererSettings } from "./settings";
|
||||
|
||||
import { debugMode, verboseMode } from "../settings";
|
||||
|
||||
import { ASS } from "../types/ass";
|
||||
import { Dialogue } from "../types/dialogue";
|
||||
|
||||
import { Clock, ClockEvent } from "./clocks/base";
|
||||
|
||||
import { RendererSettings } from "./settings";
|
||||
|
||||
/**
|
||||
* A renderer implementation that doesn't output anything.
|
||||
*
|
||||
@@ -35,7 +35,7 @@ import { RendererSettings } from "./settings";
|
||||
* @param {libjass.renderers.RendererSettings} settings
|
||||
*/
|
||||
export class NullRenderer {
|
||||
private static _lastRendererId: number = -1;
|
||||
private static _lastRendererId = -1;
|
||||
|
||||
private _id: number;
|
||||
|
||||
@@ -88,14 +88,14 @@ export class NullRenderer {
|
||||
*
|
||||
* @param {!libjass.Dialogue} dialogue
|
||||
*/
|
||||
preRender(_dialogue: Dialogue): void { }
|
||||
preRender(dialogue: Dialogue): void { }
|
||||
|
||||
/**
|
||||
* Draw a dialogue. This is a no-op for this type.
|
||||
*
|
||||
* @param {!libjass.Dialogue} dialogue
|
||||
*/
|
||||
draw(_dialogue: Dialogue): void { }
|
||||
draw(dialogue: Dialogue): void { }
|
||||
|
||||
/**
|
||||
* Enable the renderer.
|
||||
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* libjass
|
||||
*
|
||||
* https://github.com/Arnavion/libjass
|
||||
*
|
||||
* Copyright 2013 Arnav Singh
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Returns the elements of an array that meet the condition specified in a callback function.
|
||||
* @param callbackfn A function that accepts up to three arguments. The filter method calls the callbackfn function one time for each element in the array.
|
||||
* @param thisArg An object to which the this keyword can refer in the callbackfn function. If thisArg is omitted, undefined is used as the this value.
|
||||
*/
|
||||
filter<S extends T>(callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[];
|
||||
}
|
||||
+74
-75
@@ -25,78 +25,6 @@ import { Map } from "../utility/map";
|
||||
* Settings for the renderer.
|
||||
*/
|
||||
export class RendererSettings {
|
||||
/**
|
||||
* A convenience method to create a font map from a <style> or <link> element that contains @font-face rules. There should be one @font-face rule for each font name, mapping to a font file URL.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* @font-face {
|
||||
* font-family: "Helvetica";
|
||||
* src: url("/fonts/helvetica.ttf"), local("Arial");
|
||||
* }
|
||||
*
|
||||
* More complicated @font-face syntax like format() or multi-line src are not supported.
|
||||
*
|
||||
* @param {!LinkStyle} linkStyle
|
||||
* @return {!Map.<string, string>}
|
||||
*/
|
||||
static makeFontMapFromStyleElement(linkStyle: LinkStyle): Map<string, string> {
|
||||
const fontMap = new Map<string, string>();
|
||||
|
||||
const styleSheet = linkStyle.sheet as CSSStyleSheet;
|
||||
/* tslint:disable-next-line:prefer-for-of */
|
||||
for (let i = 0; i < styleSheet.cssRules.length; i++) {
|
||||
const rule = styleSheet.cssRules[i];
|
||||
|
||||
if (isFontFaceRule(rule)) {
|
||||
const name = rule.style.getPropertyValue("font-family").match(/^["']?(.*?)["']?$/)![1];
|
||||
|
||||
let src = rule.style.getPropertyValue("src");
|
||||
if (!src) {
|
||||
src = rule.cssText.split("\n")
|
||||
.map(line => line.match(/src:\s*([^;]+?)\s*;/))
|
||||
.filter((matches): matches is RegExpMatchArray => matches !== null)
|
||||
.map(matches => matches[1])[0];
|
||||
}
|
||||
|
||||
fontMap.set(name, src);
|
||||
}
|
||||
}
|
||||
|
||||
return fontMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an arbitrary object into a {@link libjass.renderers.RendererSettings} object.
|
||||
*
|
||||
* @param {*} object
|
||||
* @return {!libjass.renderers.RendererSettings}
|
||||
*/
|
||||
static from(object?: any): RendererSettings {
|
||||
if (object === undefined || object === null) {
|
||||
object = {};
|
||||
}
|
||||
|
||||
const {
|
||||
fontMap = null,
|
||||
preRenderTime = 5,
|
||||
preciseOutlines = false,
|
||||
enableSvg = testSupportsSvg(),
|
||||
fallbackFonts = 'Arial, Helvetica, sans-serif, "Segoe UI Symbol"',
|
||||
useAttachedFonts = false,
|
||||
} = object as RendererSettings;
|
||||
|
||||
const result = new RendererSettings();
|
||||
result.fontMap = fontMap;
|
||||
result.preRenderTime = preRenderTime;
|
||||
result.preciseOutlines = preciseOutlines;
|
||||
result.enableSvg = enableSvg;
|
||||
result.fallbackFonts = fallbackFonts;
|
||||
result.useAttachedFonts = useAttachedFonts;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* A map of font name to one or more URLs of that font. If provided, the fonts in this map are pre-loaded by the WebRenderer when it's created.
|
||||
*
|
||||
@@ -169,6 +97,77 @@ export class RendererSettings {
|
||||
* @type {boolean}
|
||||
*/
|
||||
useAttachedFonts: boolean;
|
||||
|
||||
/**
|
||||
* A convenience method to create a font map from a <style> or <link> element that contains @font-face rules. There should be one @font-face rule for each font name, mapping to a font file URL.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* @font-face {
|
||||
* font-family: "Helvetica";
|
||||
* src: url("/fonts/helvetica.ttf"), local("Arial");
|
||||
* }
|
||||
*
|
||||
* More complicated @font-face syntax like format() or multi-line src are not supported.
|
||||
*
|
||||
* @param {!LinkStyle} linkStyle
|
||||
* @return {!Map.<string, string>}
|
||||
*/
|
||||
static makeFontMapFromStyleElement(linkStyle: LinkStyle): Map<string, string> {
|
||||
const fontMap = new Map<string, string>();
|
||||
|
||||
const styleSheet = linkStyle.sheet as CSSStyleSheet;
|
||||
for (let i = 0; i < styleSheet.cssRules.length; i++) {
|
||||
const rule = styleSheet.cssRules[i];
|
||||
|
||||
if (isFontFaceRule(rule)) {
|
||||
const name = rule.style.getPropertyValue("font-family").match(/^["']?(.*?)["']?$/)![1];
|
||||
|
||||
let src = rule.style.getPropertyValue("src");
|
||||
if (!src) {
|
||||
src = rule.cssText.split("\n")
|
||||
.map(line => line.match(/src:\s*([^;]+?)\s*;/))
|
||||
.filter((matches): matches is RegExpMatchArray => matches !== null)
|
||||
.map(matches => matches[1])[0];
|
||||
}
|
||||
|
||||
fontMap.set(name, src);
|
||||
}
|
||||
}
|
||||
|
||||
return fontMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an arbitrary object into a {@link libjass.renderers.RendererSettings} object.
|
||||
*
|
||||
* @param {*} object
|
||||
* @return {!libjass.renderers.RendererSettings}
|
||||
*/
|
||||
static from(object?: any): RendererSettings {
|
||||
if (object === undefined || object === null) {
|
||||
object = {};
|
||||
}
|
||||
|
||||
const {
|
||||
fontMap = null,
|
||||
preRenderTime = 5,
|
||||
preciseOutlines = false,
|
||||
enableSvg = testSupportsSvg(),
|
||||
fallbackFonts = 'Arial, Helvetica, sans-serif, "Segoe UI Symbol"',
|
||||
useAttachedFonts = false,
|
||||
} = object as RendererSettings;
|
||||
|
||||
const result = new RendererSettings();
|
||||
result.fontMap = fontMap;
|
||||
result.preRenderTime = preRenderTime;
|
||||
result.preciseOutlines = preciseOutlines;
|
||||
result.enableSvg = enableSvg;
|
||||
result.fallbackFonts = fallbackFonts;
|
||||
result.useAttachedFonts = useAttachedFonts;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,7 +188,7 @@ function testSupportsSvg(): boolean {
|
||||
console.log("Testing whether SVG filter effects are supported.");
|
||||
}
|
||||
|
||||
if (global.document === undefined) {
|
||||
if (typeof document === "undefined") {
|
||||
if (debugMode) {
|
||||
console.log("This doesn't look like a browser. Assuming it doesn't support SVG filter effects.");
|
||||
}
|
||||
@@ -199,7 +198,7 @@ function testSupportsSvg(): boolean {
|
||||
|
||||
const morphologyFilter = document.createElementNS("http://www.w3.org/2000/svg", "feMorphology");
|
||||
|
||||
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6618301/
|
||||
// https://connect.microsoft.com/IE/feedback/details/2375800
|
||||
try {
|
||||
morphologyFilter.radiusX.baseVal = 1;
|
||||
}
|
||||
@@ -222,7 +221,7 @@ function testSupportsSvg(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
// https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/6618454/
|
||||
// https://connect.microsoft.com/IE/feedback/details/2375757
|
||||
morphologyFilter.setAttribute("radius", "1");
|
||||
if (morphologyFilter.cloneNode().getAttribute("radius") !== "1") {
|
||||
if (debugMode) {
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
import { Promise } from "../../utility/promise";
|
||||
|
||||
/**
|
||||
@@ -46,7 +47,7 @@ function prepareFontSizeElement(fontFamily: string, fontSize: number, fallbackFo
|
||||
function lineHeightForFontSize(fontFamily: string, fontSize: number, fallbackFonts: string, fontSizeElement: HTMLDivElement): Promise<number> {
|
||||
prepareFontSizeElement(fontFamily, fontSize, fallbackFonts, fontSizeElement);
|
||||
|
||||
return new Promise<number>(resolve => setTimeout(() => resolve(fontSizeElement.offsetHeight), 1000));
|
||||
return new Promise(resolve => setTimeout(() => resolve(fontSizeElement.offsetHeight), 1000));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -77,12 +78,14 @@ function fontMetricsFromLineHeights(lowerLineHeight: number, upperLineHeight: nu
|
||||
* @param {string} fontFamily
|
||||
* @param {string} fallbackFonts
|
||||
* @param {!HTMLDivElement} fontSizeElement
|
||||
* @return {!Promise.<[number, number]>}
|
||||
* @return {!Promise.<number>}
|
||||
*/
|
||||
export function calculateFontMetrics(fontFamily: string, fallbackFonts: string, fontSizeElement: HTMLDivElement): Promise<[number, number]> {
|
||||
return lineHeightForFontSize(fontFamily, 180, fallbackFonts, fontSizeElement).then(lowerLineHeight =>
|
||||
lineHeightForFontSize(fontFamily, 360, fallbackFonts, fontSizeElement).then(upperLineHeight =>
|
||||
fontMetricsFromLineHeights(lowerLineHeight, upperLineHeight)));
|
||||
fontMetricsFromLineHeights(lowerLineHeight, upperLineHeight)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
|
||||
/**
|
||||
* This class represents a single keyframe. It has a list of CSS properties (names and values) associated with a point in time. Multiple keyframes make up an animation.
|
||||
*
|
||||
|
||||
+153
-135
@@ -18,6 +18,17 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { AnimationCollection } from "./animation-collection";
|
||||
import { DrawingStyles } from "./drawing-styles";
|
||||
import { calculateFontMetrics } from "./font-size";
|
||||
import { Keyframe } from "./keyframe";
|
||||
import { SpanStyles } from "./span-styles";
|
||||
|
||||
import { Clock, EventSource } from "../clocks/base";
|
||||
|
||||
import { NullRenderer } from "../null";
|
||||
import { RendererSettings } from "../settings";
|
||||
|
||||
import { getTtfNames } from "../../parser/ttf";
|
||||
|
||||
import * as parts from "../../parts";
|
||||
@@ -29,20 +40,44 @@ import { AttachmentType } from "../../types/attachment";
|
||||
import { Dialogue } from "../../types/dialogue";
|
||||
import { WrappingStyle } from "../../types/misc";
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
import { mixin } from "../../utility/mixin";
|
||||
import { any as Promise_any, first as Promise_first, lastly as Promise_finally, Promise } from "../../utility/promise";
|
||||
import { Map } from "../../utility/map";
|
||||
import { Promise, any as Promise_any, first as Promise_first, lastly as Promise_finally } from "../../utility/promise";
|
||||
import { Set } from "../../utility/set";
|
||||
|
||||
import { Clock, EventSource } from "../clocks/base";
|
||||
declare const global: {
|
||||
document: {
|
||||
fonts?: FontFaceSet;
|
||||
};
|
||||
};
|
||||
|
||||
import { NullRenderer } from "../null";
|
||||
import { RendererSettings } from "../settings";
|
||||
interface FontFaceSet {
|
||||
/**
|
||||
* @param {!FontFace} fontFace
|
||||
* @return {!FontFaceSet}
|
||||
*/
|
||||
add(fontFace: FontFace): FontFaceSet;
|
||||
|
||||
import { AnimationCollection } from "./animation-collection";
|
||||
import { DrawingStyles } from "./drawing-styles";
|
||||
import { calculateFontMetrics } from "./font-size";
|
||||
import { Keyframe } from "./keyframe";
|
||||
import { SpanStyles } from "./span-styles";
|
||||
/**
|
||||
* @param {function(!FontFace, !FontFace, !FontFaceSet)} callbackfn A function that is called with each value in the set.
|
||||
* @param {*} thisArg
|
||||
*/
|
||||
forEach(callbackfn: (fontFace: FontFace, index: FontFace, set: FontFaceSet) => void, thisArg?: any): void;
|
||||
}
|
||||
|
||||
interface FontFace {
|
||||
/** @type {string} */
|
||||
family: string;
|
||||
|
||||
/**
|
||||
* @return {!Promise.<!FontFace>}
|
||||
*/
|
||||
load(): Promise<FontFace>;
|
||||
}
|
||||
|
||||
declare var FontFace: {
|
||||
new (family: string, source: string): FontFace;
|
||||
};
|
||||
|
||||
const fontSrcUrlRegex = /^(url|local)\(["']?(.+?)["']?\)$/;
|
||||
|
||||
@@ -57,18 +92,11 @@ const fontSrcUrlRegex = /^(url|local)\(["']?(.+?)["']?\)$/;
|
||||
* @param {!libjass.renderers.RendererSettings} settings
|
||||
*/
|
||||
export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
private static _transformOrigins: number[][] = [
|
||||
[],
|
||||
[0, 100], [50, 100], [100, 100],
|
||||
[0, 50], [50, 50], [100, 50],
|
||||
[0, 0], [50, 0], [100, 0],
|
||||
];
|
||||
|
||||
private _subsWrapper: HTMLDivElement;
|
||||
private _subsWrapperWidth: number; // this._subsWrapper.offsetWidth is expensive, so cache this.
|
||||
|
||||
private _layerWrappers: (HTMLDivElement | undefined)[] = [];
|
||||
private _layerAlignmentWrappers: (HTMLDivElement | undefined)[][] = [];
|
||||
private _layerWrappers: HTMLDivElement[] = [];
|
||||
private _layerAlignmentWrappers: HTMLDivElement[][] = [];
|
||||
private _fontSizeElement: HTMLDivElement;
|
||||
|
||||
private _fontMetricsCache: Map<string, [number, number]> = new Map<string, [number, number]>();
|
||||
@@ -133,7 +161,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
const attachmentUrl = `data:application/x-font-ttf;base64,${ attachment.contents }`;
|
||||
|
||||
ttfNames.forEach(name => {
|
||||
const correspondingFontMapEntry = fontMap.get(name);
|
||||
let correspondingFontMapEntry = fontMap.get(name);
|
||||
if (correspondingFontMapEntry !== undefined) {
|
||||
// Also defined in fontMap.
|
||||
if (typeof correspondingFontMapEntry !== "string") {
|
||||
@@ -163,7 +191,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
fontMap.forEach((srcs, fontFamily) => {
|
||||
let fontFamilyMetricsPromise: Promise<[number, number]>;
|
||||
|
||||
if (global.document && global.document.fonts && global.document.fonts!.add) {
|
||||
if (global.document.fonts && global.document.fonts.add) {
|
||||
// value should be string. If it's string[], combine it into string
|
||||
let source =
|
||||
(typeof srcs === "string") ?
|
||||
@@ -180,7 +208,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
}
|
||||
|
||||
const existingFontFaces: FontFace[] = [];
|
||||
let existingFontFaces: FontFace[] = [];
|
||||
global.document.fonts.forEach(fontFace => {
|
||||
if (fontFace.family === fontFamily || fontFace.family === `"${ fontFamily }"`) {
|
||||
existingFontFaces.push(fontFace);
|
||||
@@ -189,8 +217,8 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
|
||||
let fontFetchPromise: Promise<FontFace | null>;
|
||||
if (existingFontFaces.length === 0) {
|
||||
const fontFace = new global.FontFace!(fontFamily, source);
|
||||
const quotedFontFace = new global.FontFace!(`"${ fontFamily }"`, source);
|
||||
const fontFace = new FontFace(fontFamily, source);
|
||||
const quotedFontFace = new FontFace(`"${ fontFamily }"`, source);
|
||||
|
||||
global.document.fonts.add(fontFace);
|
||||
global.document.fonts.add(quotedFontFace);
|
||||
@@ -274,7 +302,6 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
preloadFontPromises.push(fontFamilyMetricsPromise.then(metrics => this._fontMetricsCache.set(fontFamily, metrics)));
|
||||
});
|
||||
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
Promise.all(preloadFontPromises).then(() => {
|
||||
if (debugMode) {
|
||||
console.log("All fonts have been preloaded.");
|
||||
@@ -401,7 +428,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
|
||||
for (const part of dialogue.parts) {
|
||||
if (part instanceof parts.Italic) {
|
||||
currentSpanStyles.italic = part.value as boolean;
|
||||
currentSpanStyles.italic = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Bold) {
|
||||
@@ -409,45 +436,45 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Underline) {
|
||||
currentSpanStyles.underline = part.value as boolean;
|
||||
currentSpanStyles.underline = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.StrikeThrough) {
|
||||
currentSpanStyles.strikeThrough = part.value as boolean;
|
||||
currentSpanStyles.strikeThrough = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Border) {
|
||||
currentSpanStyles.outlineWidth = part.value as number;
|
||||
currentSpanStyles.outlineHeight = part.value as number;
|
||||
currentSpanStyles.outlineWidth = part.value;
|
||||
currentSpanStyles.outlineHeight = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.BorderX) {
|
||||
currentSpanStyles.outlineWidth = part.value as number;
|
||||
currentSpanStyles.outlineWidth = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.BorderY) {
|
||||
currentSpanStyles.outlineHeight = part.value as number;
|
||||
currentSpanStyles.outlineHeight = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Shadow) {
|
||||
currentSpanStyles.shadowDepthX = part.value as number;
|
||||
currentSpanStyles.shadowDepthY = part.value as number;
|
||||
currentSpanStyles.shadowDepthX = part.value;
|
||||
currentSpanStyles.shadowDepthY = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.ShadowX) {
|
||||
currentSpanStyles.shadowDepthX = part.value as number;
|
||||
currentSpanStyles.shadowDepthX = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.ShadowY) {
|
||||
currentSpanStyles.shadowDepthY = part.value as number;
|
||||
currentSpanStyles.shadowDepthY = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Blur) {
|
||||
currentSpanStyles.blur = part.value as number;
|
||||
currentSpanStyles.blur = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.GaussianBlur) {
|
||||
currentSpanStyles.gaussianBlur = part.value as number;
|
||||
currentSpanStyles.gaussianBlur = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.FontName) {
|
||||
@@ -455,7 +482,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
|
||||
else if (part instanceof parts.FontSize) {
|
||||
currentSpanStyles.fontSize = part.value as number;
|
||||
currentSpanStyles.fontSize = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.FontSizePlus) {
|
||||
@@ -467,74 +494,74 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
|
||||
else if (part instanceof parts.FontScaleX) {
|
||||
currentSpanStyles.fontScaleX = part.value as number;
|
||||
currentSpanStyles.fontScaleX = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.FontScaleY) {
|
||||
currentSpanStyles.fontScaleY = part.value as number;
|
||||
currentSpanStyles.fontScaleY = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.LetterSpacing) {
|
||||
currentSpanStyles.letterSpacing = part.value as number;
|
||||
currentSpanStyles.letterSpacing = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.RotateX) {
|
||||
currentSpanStyles.rotationX = part.value as number;
|
||||
currentSpanStyles.rotationX = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.RotateY) {
|
||||
currentSpanStyles.rotationY = part.value as number;
|
||||
currentSpanStyles.rotationY = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.RotateZ) {
|
||||
currentSpanStyles.rotationZ = part.value as number;
|
||||
currentSpanStyles.rotationZ = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.SkewX) {
|
||||
currentSpanStyles.skewX = part.value as number;
|
||||
currentSpanStyles.skewX = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.SkewY) {
|
||||
currentSpanStyles.skewY = part.value as number;
|
||||
currentSpanStyles.skewY = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.PrimaryColor) {
|
||||
currentSpanStyles.primaryColor = part.value as parts.Color;
|
||||
currentSpanStyles.primaryColor = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.SecondaryColor) {
|
||||
currentSpanStyles.secondaryColor = part.value as parts.Color;
|
||||
currentSpanStyles.secondaryColor = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.OutlineColor) {
|
||||
currentSpanStyles.outlineColor = part.value as parts.Color;
|
||||
currentSpanStyles.outlineColor = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.ShadowColor) {
|
||||
currentSpanStyles.shadowColor = part.value as parts.Color;
|
||||
currentSpanStyles.shadowColor = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Alpha) {
|
||||
currentSpanStyles.primaryAlpha = part.value as number;
|
||||
currentSpanStyles.secondaryAlpha = part.value as number;
|
||||
currentSpanStyles.outlineAlpha = part.value as number;
|
||||
currentSpanStyles.shadowAlpha = part.value as number;
|
||||
currentSpanStyles.primaryAlpha = part.value;
|
||||
currentSpanStyles.secondaryAlpha = part.value;
|
||||
currentSpanStyles.outlineAlpha = part.value;
|
||||
currentSpanStyles.shadowAlpha = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.PrimaryAlpha) {
|
||||
currentSpanStyles.primaryAlpha = part.value as number;
|
||||
currentSpanStyles.primaryAlpha = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.SecondaryAlpha) {
|
||||
currentSpanStyles.secondaryAlpha = part.value as number;
|
||||
currentSpanStyles.secondaryAlpha = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.OutlineAlpha) {
|
||||
currentSpanStyles.outlineAlpha = part.value as number;
|
||||
currentSpanStyles.outlineAlpha = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.ShadowAlpha) {
|
||||
currentSpanStyles.shadowAlpha = part.value as number;
|
||||
currentSpanStyles.shadowAlpha = part.value;
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Alignment) {
|
||||
@@ -546,10 +573,10 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
|
||||
currentAnimationCollection!.add("step-end", [
|
||||
new Keyframe(0, new Map([
|
||||
["color", currentSpanStyles.secondaryColor.withAlpha(currentSpanStyles.secondaryAlpha).toString()],
|
||||
["color", currentSpanStyles.secondaryColor!.withAlpha(currentSpanStyles.secondaryAlpha!).toString()],
|
||||
])), new Keyframe(karaokeTimesAccumulator, new Map([
|
||||
["color", currentSpanStyles.primaryColor.withAlpha(currentSpanStyles.primaryAlpha).toString()],
|
||||
])),
|
||||
["color", currentSpanStyles.primaryColor!.withAlpha(currentSpanStyles.primaryAlpha!).toString()],
|
||||
]))
|
||||
]);
|
||||
|
||||
karaokeTimesAccumulator += part.duration;
|
||||
@@ -593,23 +620,15 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
|
||||
else if (part instanceof parts.Fade) {
|
||||
const keyframes: Keyframe[] = [];
|
||||
if (part.start !== 0) {
|
||||
keyframes.push(new Keyframe(0, new Map([
|
||||
["opacity", "0"],
|
||||
])));
|
||||
}
|
||||
keyframes.push(new Keyframe(part.start, new Map([
|
||||
dialogueAnimationCollection.add("linear", [new Keyframe(0, new Map([
|
||||
["opacity", "0"],
|
||||
])), new Keyframe(part.start, new Map([
|
||||
["opacity", "1"],
|
||||
])), new Keyframe(dialogue.end - dialogue.start - part.end, new Map([
|
||||
["opacity", "1"],
|
||||
])));
|
||||
if (part.end !== 0) {
|
||||
keyframes.push(new Keyframe(dialogue.end - dialogue.start, new Map([
|
||||
["opacity", "0"],
|
||||
])));
|
||||
}
|
||||
dialogueAnimationCollection.add("linear", keyframes);
|
||||
])), new Keyframe(dialogue.end - dialogue.start, new Map([
|
||||
["opacity", "0"],
|
||||
]))]);
|
||||
}
|
||||
|
||||
else if (part instanceof parts.ComplexFade) {
|
||||
@@ -630,9 +649,9 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
|
||||
else if (part instanceof parts.Transform) {
|
||||
const progression =
|
||||
(currentTimeRelativeToDialogueStart <= part.start!) ? 0 :
|
||||
(currentTimeRelativeToDialogueStart >= part.end!) ? 1 :
|
||||
Math.pow((currentTimeRelativeToDialogueStart - part.start!) / (part.end! - part.start!), part.accel!);
|
||||
(currentTimeRelativeToDialogueStart <= part.start) ? 0 :
|
||||
(currentTimeRelativeToDialogueStart >= part.end) ? 1 :
|
||||
Math.pow((currentTimeRelativeToDialogueStart - part.start) / (part.end - part.start), part.accel!);
|
||||
|
||||
for (const tag of part.tags) {
|
||||
if (tag instanceof parts.Border) {
|
||||
@@ -641,8 +660,8 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.outlineHeight += progression * (tag.value - currentSpanStyles.outlineHeight);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.outlineWidth = null as any as number;
|
||||
currentSpanStyles.outlineHeight = null as any as number;
|
||||
currentSpanStyles.outlineWidth = null;
|
||||
currentSpanStyles.outlineHeight = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,7 +670,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.outlineWidth += progression * (tag.value - currentSpanStyles.outlineWidth);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.outlineWidth = null as any as number;
|
||||
currentSpanStyles.outlineWidth = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -660,7 +679,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.outlineHeight += progression * (tag.value - currentSpanStyles.outlineHeight);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.outlineHeight = null as any as number;
|
||||
currentSpanStyles.outlineHeight = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -670,8 +689,8 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.shadowDepthY += progression * (tag.value - currentSpanStyles.shadowDepthY);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.shadowDepthX = null as any as number;
|
||||
currentSpanStyles.shadowDepthY = null as any as number;
|
||||
currentSpanStyles.shadowDepthX = null;
|
||||
currentSpanStyles.shadowDepthY = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -680,7 +699,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.shadowDepthX += progression * (tag.value - currentSpanStyles.shadowDepthX);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.shadowDepthX = null as any as number;
|
||||
currentSpanStyles.shadowDepthX = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -689,7 +708,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.shadowDepthY += progression * (tag.value - currentSpanStyles.shadowDepthY);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.shadowDepthY = null as any as number;
|
||||
currentSpanStyles.shadowDepthY = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -698,7 +717,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.blur += progression * (tag.value - currentSpanStyles.blur);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.blur = null as any as number;
|
||||
currentSpanStyles.blur = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -707,7 +726,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.gaussianBlur += progression * (tag.value - currentSpanStyles.gaussianBlur);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.gaussianBlur = null as any as number;
|
||||
currentSpanStyles.gaussianBlur = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,7 +735,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.fontSize += progression * (tag.value - currentSpanStyles.fontSize);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.fontSize = null as any as number;
|
||||
currentSpanStyles.fontSize = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -733,7 +752,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.fontScaleX += progression * (tag.value - currentSpanStyles.fontScaleX);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.fontScaleX = null as any as number;
|
||||
currentSpanStyles.fontScaleX = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -742,7 +761,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.fontScaleY += progression * (tag.value - currentSpanStyles.fontScaleY);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.fontScaleY = null as any as number;
|
||||
currentSpanStyles.fontScaleY = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -751,7 +770,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.letterSpacing += progression * (tag.value - currentSpanStyles.letterSpacing);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.letterSpacing = null as any as number;
|
||||
currentSpanStyles.letterSpacing = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -760,7 +779,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.rotationX += progression * (tag.value - currentSpanStyles.rotationX);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.rotationX = null as any as number;
|
||||
currentSpanStyles.rotationX = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -769,7 +788,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.rotationY += progression * (tag.value - currentSpanStyles.rotationY);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.rotationY = null as any as number;
|
||||
currentSpanStyles.rotationY = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -778,7 +797,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.rotationZ += progression * (tag.value - currentSpanStyles.rotationZ);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.rotationZ = null as any as number;
|
||||
currentSpanStyles.rotationZ = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -787,7 +806,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.skewX += progression * (tag.value - currentSpanStyles.skewX);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.skewX = null as any as number;
|
||||
currentSpanStyles.skewX = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -796,43 +815,43 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.skewY += progression * (tag.value - currentSpanStyles.skewY);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.skewY = null as any as number;
|
||||
currentSpanStyles.skewY = null;
|
||||
}
|
||||
}
|
||||
|
||||
else if (tag instanceof parts.PrimaryColor) {
|
||||
if (tag.value !== null) {
|
||||
currentSpanStyles.primaryColor = currentSpanStyles.primaryColor.interpolate(tag.value, progression);
|
||||
currentSpanStyles.primaryColor = currentSpanStyles.primaryColor!.interpolate(tag.value, progression);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.primaryColor = null as any as parts.Color;
|
||||
currentSpanStyles.primaryColor = null;
|
||||
}
|
||||
}
|
||||
|
||||
else if (tag instanceof parts.SecondaryColor) {
|
||||
if (tag.value !== null) {
|
||||
currentSpanStyles.secondaryColor = currentSpanStyles.secondaryColor.interpolate(tag.value, progression);
|
||||
currentSpanStyles.secondaryColor = currentSpanStyles.secondaryColor!.interpolate(tag.value, progression);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.secondaryColor = null as any as parts.Color;
|
||||
currentSpanStyles.secondaryColor = null;
|
||||
}
|
||||
}
|
||||
|
||||
else if (tag instanceof parts.OutlineColor) {
|
||||
if (tag.value !== null) {
|
||||
currentSpanStyles.outlineColor = currentSpanStyles.outlineColor.interpolate(tag.value, progression);
|
||||
currentSpanStyles.outlineColor = currentSpanStyles.outlineColor!.interpolate(tag.value, progression);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.outlineColor = null as any as parts.Color;
|
||||
currentSpanStyles.outlineColor = null;
|
||||
}
|
||||
}
|
||||
|
||||
else if (tag instanceof parts.ShadowColor) {
|
||||
if (tag.value !== null) {
|
||||
currentSpanStyles.shadowColor = currentSpanStyles.shadowColor.interpolate(tag.value, progression);
|
||||
currentSpanStyles.shadowColor = currentSpanStyles.shadowColor!.interpolate(tag.value, progression);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.shadowColor = null as any as parts.Color;
|
||||
currentSpanStyles.shadowColor = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -844,10 +863,10 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.shadowAlpha += progression * (tag.value - currentSpanStyles.shadowAlpha);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.primaryAlpha = null as any as number;
|
||||
currentSpanStyles.secondaryAlpha = null as any as number;
|
||||
currentSpanStyles.outlineAlpha = null as any as number;
|
||||
currentSpanStyles.shadowAlpha = null as any as number;
|
||||
currentSpanStyles.primaryAlpha = null;
|
||||
currentSpanStyles.secondaryAlpha = null;
|
||||
currentSpanStyles.outlineAlpha = null;
|
||||
currentSpanStyles.shadowAlpha = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -856,7 +875,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.primaryAlpha += progression * (tag.value - currentSpanStyles.primaryAlpha);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.primaryAlpha = null as any as number;
|
||||
currentSpanStyles.primaryAlpha = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -865,7 +884,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.secondaryAlpha += progression * (tag.value - currentSpanStyles.secondaryAlpha);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.secondaryAlpha = null as any as number;
|
||||
currentSpanStyles.secondaryAlpha = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -874,7 +893,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.outlineAlpha += progression * (tag.value - currentSpanStyles.outlineAlpha);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.outlineAlpha = null as any as number;
|
||||
currentSpanStyles.outlineAlpha = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -883,7 +902,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
currentSpanStyles.shadowAlpha += progression * (tag.value - currentSpanStyles.shadowAlpha);
|
||||
}
|
||||
else {
|
||||
currentSpanStyles.shadowAlpha = null as any as number;
|
||||
currentSpanStyles.shadowAlpha = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -900,7 +919,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
}
|
||||
|
||||
else if (part instanceof parts.DrawingInstructions) {
|
||||
currentSpan!.appendChild(currentDrawingStyles.toSVG(part, currentSpanStyles.primaryColor.withAlpha(currentSpanStyles.primaryAlpha)));
|
||||
currentSpan!.appendChild(currentDrawingStyles.toSVG(part, currentSpanStyles.primaryColor!.withAlpha(currentSpanStyles.primaryAlpha!)));
|
||||
startNewSpan(false);
|
||||
}
|
||||
|
||||
@@ -917,15 +936,6 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
else if (part instanceof parts.NewLine) {
|
||||
startNewSpan(true);
|
||||
}
|
||||
|
||||
else if (part instanceof parts.SoftNewLine) {
|
||||
if (wrappingStyle === WrappingStyle.NoLineWrapping) {
|
||||
startNewSpan(true);
|
||||
}
|
||||
else {
|
||||
currentSpan!.appendChild(document.createTextNode(" "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let divTransformStyle = "";
|
||||
@@ -1038,7 +1048,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
if (animationNames !== "") {
|
||||
const animationDelays = animationNames.split(",").map(name => {
|
||||
name = name.trim();
|
||||
const delay = preRenderedSub.animationDelays.get(name)!;
|
||||
const delay = preRenderedSub.animationDelays.get(name);
|
||||
return `${ ((delay + dialogue.start - this.clock.currentTime) / this.clock.rate).toFixed(3) }s`;
|
||||
}).join(", ");
|
||||
|
||||
@@ -1048,7 +1058,6 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
};
|
||||
applyAnimationDelays(result);
|
||||
const animatedDescendants = result.querySelectorAll('[style*="animation:"]');
|
||||
/* tslint:disable-next-line:prefer-for-of */
|
||||
for (let i = 0; i < animatedDescendants.length; i++) {
|
||||
applyAnimationDelays(animatedDescendants[i] as HTMLElement);
|
||||
}
|
||||
@@ -1065,7 +1074,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
let insertBeforeElement: HTMLDivElement | null = null;
|
||||
for (let insertBeforeLayer = layer + 1; insertBeforeLayer < this._layerWrappers.length && insertBeforeElement === null; insertBeforeLayer++) {
|
||||
if (this._layerWrappers[insertBeforeLayer] !== undefined) {
|
||||
insertBeforeElement = this._layerWrappers[insertBeforeLayer]!;
|
||||
insertBeforeElement = this._layerWrappers[insertBeforeLayer];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1081,11 +1090,11 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
layerAlignmentWrapper.className = `an an${ alignment }`;
|
||||
|
||||
// Find the next greater layer,alignment div and insert this div before that one
|
||||
const layerWrapper = this._layerWrappers[layer]!;
|
||||
const layerWrapper = this._layerWrappers[layer];
|
||||
let insertBeforeElement: HTMLDivElement | null = null;
|
||||
for (let insertBeforeAlignment = alignment + 1; insertBeforeAlignment < this._layerAlignmentWrappers[layer].length && insertBeforeElement === null; insertBeforeAlignment++) {
|
||||
if (this._layerAlignmentWrappers[layer][insertBeforeAlignment] !== undefined) {
|
||||
insertBeforeElement = this._layerAlignmentWrappers[layer][insertBeforeAlignment]!;
|
||||
insertBeforeElement = this._layerAlignmentWrappers[layer][insertBeforeAlignment];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1103,7 +1112,6 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
|
||||
// Workaround for IE
|
||||
const dialogueAnimationStylesElement = result.getElementsByTagName("style")[0];
|
||||
/* tslint:disable-next-line:strict-type-predicates */
|
||||
if (dialogueAnimationStylesElement !== undefined) {
|
||||
const sheet = dialogueAnimationStylesElement.sheet as CSSStyleSheet;
|
||||
if (sheet.cssRules.length === 0) {
|
||||
@@ -1132,7 +1140,7 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
this._currentSubs.forEach((sub: HTMLDivElement, dialogue: Dialogue) => {
|
||||
if (dialogue.start > currentTime || dialogue.end < currentTime || dialogue.containsTransformTag) {
|
||||
this._currentSubs.delete(dialogue);
|
||||
sub.parentNode!.removeChild(sub);
|
||||
this._removeSub(sub);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1177,12 +1185,24 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!HTMLDivElement} sub
|
||||
*/
|
||||
private _removeSub(sub: HTMLDivElement): void {
|
||||
sub.parentNode.removeChild(sub);
|
||||
}
|
||||
|
||||
private _removeAllSubs(): void {
|
||||
this._currentSubs.forEach((sub: HTMLDivElement) => sub.parentNode!.removeChild(sub));
|
||||
this._currentSubs.forEach((sub: HTMLDivElement) => this._removeSub(sub));
|
||||
this._currentSubs.clear();
|
||||
}
|
||||
|
||||
/* tslint:disable:member-ordering */
|
||||
private static _transformOrigins: number[][] = [
|
||||
[],
|
||||
[0, 100], [50, 100], [100, 100],
|
||||
[0, 50], [50, 50], [100, 50],
|
||||
[0, 0], [50, 0], [100, 0]
|
||||
];
|
||||
|
||||
// EventSource members
|
||||
|
||||
@@ -1200,8 +1220,6 @@ export class WebRenderer extends NullRenderer implements EventSource<string> {
|
||||
* @type {function(number, Array.<*>)}
|
||||
*/
|
||||
_dispatchEvent: (type: string, args: Object[]) => void;
|
||||
|
||||
/* tslint:enable:member-ordering */
|
||||
}
|
||||
mixin(WebRenderer, [EventSource]);
|
||||
|
||||
|
||||
@@ -18,16 +18,20 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Color } from "../../parts";
|
||||
import { AnimationCollection } from "./animation-collection";
|
||||
|
||||
import { Dialogue } from "../../types/dialogue";
|
||||
import { Style } from "../../types/style";
|
||||
import { fontSizeForLineHeight } from "./font-size";
|
||||
|
||||
import { WebRenderer } from "./renderer";
|
||||
|
||||
import { RendererSettings } from "../settings";
|
||||
|
||||
import { AnimationCollection } from "./animation-collection";
|
||||
import { fontSizeForLineHeight } from "./font-size";
|
||||
import { WebRenderer } from "./renderer";
|
||||
import { Color } from "../../parts";
|
||||
|
||||
import { Style } from "../../types/style";
|
||||
import { Dialogue } from "../../types/dialogue";
|
||||
|
||||
import { Map } from "../../utility/map";
|
||||
|
||||
/**
|
||||
* This class represents the style attribute of a span.
|
||||
@@ -85,7 +89,7 @@ export class SpanStyles {
|
||||
private _blur: number;
|
||||
private _gaussianBlur: number;
|
||||
|
||||
private _nextFilterId: number = 0;
|
||||
private _nextFilterId = 0;
|
||||
|
||||
constructor(renderer: WebRenderer, dialogue: Dialogue, private _scaleX: number, private _scaleY: number, private _settings: RendererSettings, private _fontSizeElement: HTMLDivElement, private _svgDefsElement: SVGDefsElement, private _fontMetricsCache: Map<string, [number, number]>) {
|
||||
this._id = `${ renderer.id }-${ dialogue.id }`;
|
||||
@@ -140,8 +144,8 @@ export class SpanStyles {
|
||||
this.outlineAlpha = newStyle.outlineColor.alpha;
|
||||
this.shadowAlpha = newStyle.shadowColor.alpha;
|
||||
|
||||
this.blur = null as any as number;
|
||||
this.gaussianBlur = null as any as number;
|
||||
this.blur = null;
|
||||
this.gaussianBlur = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -162,7 +166,7 @@ export class SpanStyles {
|
||||
fontStyleOrWeight += "bold ";
|
||||
}
|
||||
else if (this._bold !== false) {
|
||||
fontStyleOrWeight += this._bold.toFixed(0) + " ";
|
||||
fontStyleOrWeight += this._bold + " ";
|
||||
}
|
||||
|
||||
const lineHeight = this._scaleY * (isTextOnlySpan ? this._fontScaleX : 1) * this._fontSize;
|
||||
@@ -253,14 +257,14 @@ export class SpanStyles {
|
||||
this._svg(
|
||||
span,
|
||||
outlineWidth, outlineHeight, outlineColor,
|
||||
shadowDepthX, shadowDepthY, shadowColor,
|
||||
shadowDepthX, shadowDepthY, shadowColor
|
||||
);
|
||||
}
|
||||
else {
|
||||
this._textShadow(
|
||||
span,
|
||||
outlineWidth, outlineHeight, outlineColor,
|
||||
shadowDepthX, shadowDepthY, shadowColor,
|
||||
shadowDepthX, shadowDepthY, shadowColor
|
||||
);
|
||||
}
|
||||
|
||||
@@ -275,15 +279,6 @@ export class SpanStyles {
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!HTMLBRElement}
|
||||
*/
|
||||
makeNewLine(): HTMLBRElement {
|
||||
const result = document.createElement("br");
|
||||
result.style.lineHeight = `${ (this._scaleY * this._fontSize).toFixed(3) }px`;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!HTMLSpanElement} span
|
||||
* @param {number} outlineWidth
|
||||
@@ -296,7 +291,7 @@ export class SpanStyles {
|
||||
private _svg(
|
||||
span: HTMLSpanElement,
|
||||
outlineWidth: number, outlineHeight: number, outlineColor: Color,
|
||||
shadowDepthX: number, shadowDepthY: number, shadowColor: Color,
|
||||
shadowDepthX: number, shadowDepthY: number, shadowColor: Color
|
||||
): void {
|
||||
const filterElement = document.createElementNS("http://www.w3.org/2000/svg", "filter");
|
||||
|
||||
@@ -533,7 +528,7 @@ export class SpanStyles {
|
||||
private _textShadow(
|
||||
span: HTMLSpanElement,
|
||||
outlineWidth: number, outlineHeight: number, outlineColor: Color,
|
||||
shadowDepthX: number, shadowDepthY: number, shadowColor: Color,
|
||||
shadowDepthX: number, shadowDepthY: number, shadowColor: Color
|
||||
): void {
|
||||
if (outlineWidth > 0 || outlineHeight > 0) {
|
||||
let outlineCssString = "";
|
||||
@@ -589,6 +584,15 @@ export class SpanStyles {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {!HTMLBRElement}
|
||||
*/
|
||||
makeNewLine(): HTMLBRElement {
|
||||
const result = document.createElement("br");
|
||||
result.style.lineHeight = `${ (this._scaleY * this._fontSize).toFixed(3) }px`;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the italic property. null defaults it to the default style's value.
|
||||
*
|
||||
@@ -630,7 +634,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get outlineWidth(): number {
|
||||
get outlineWidth(): number | null {
|
||||
return this._outlineWidth;
|
||||
}
|
||||
|
||||
@@ -639,7 +643,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set outlineWidth(value: number) {
|
||||
set outlineWidth(value: number | null) {
|
||||
this._outlineWidth = valueOrDefault(value, this._defaultStyle.outlineThickness);
|
||||
}
|
||||
|
||||
@@ -648,7 +652,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get outlineHeight(): number {
|
||||
get outlineHeight(): number | null {
|
||||
return this._outlineHeight;
|
||||
}
|
||||
|
||||
@@ -657,7 +661,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set outlineHeight(value: number) {
|
||||
set outlineHeight(value: number | null) {
|
||||
this._outlineHeight = valueOrDefault(value, this._defaultStyle.outlineThickness);
|
||||
}
|
||||
|
||||
@@ -666,7 +670,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get shadowDepthX(): number {
|
||||
get shadowDepthX(): number | null {
|
||||
return this._shadowDepthX;
|
||||
}
|
||||
|
||||
@@ -675,7 +679,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set shadowDepthX(value: number) {
|
||||
set shadowDepthX(value: number | null) {
|
||||
this._shadowDepthX = valueOrDefault(value, this._defaultStyle.shadowDepth);
|
||||
}
|
||||
|
||||
@@ -684,7 +688,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get shadowDepthY(): number {
|
||||
get shadowDepthY(): number | null {
|
||||
return this._shadowDepthY;
|
||||
}
|
||||
|
||||
@@ -693,7 +697,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set shadowDepthY(value: number) {
|
||||
set shadowDepthY(value: number | null) {
|
||||
this._shadowDepthY = valueOrDefault(value, this._defaultStyle.shadowDepth);
|
||||
}
|
||||
|
||||
@@ -702,7 +706,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get blur(): number {
|
||||
get blur(): number | null {
|
||||
return this._blur;
|
||||
}
|
||||
|
||||
@@ -711,8 +715,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set blur(value: number) {
|
||||
this._blur = valueOrDefault<number>(value, 0);
|
||||
set blur(value: number | null) {
|
||||
this._blur = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -720,7 +724,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get gaussianBlur(): number {
|
||||
get gaussianBlur(): number | null {
|
||||
return this._gaussianBlur;
|
||||
}
|
||||
|
||||
@@ -729,8 +733,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set gaussianBlur(value: number) {
|
||||
this._gaussianBlur = valueOrDefault<number>(value, 0);
|
||||
set gaussianBlur(value: number | null) {
|
||||
this._gaussianBlur = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -747,7 +751,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get fontSize(): number {
|
||||
get fontSize(): number | null {
|
||||
return this._fontSize;
|
||||
}
|
||||
|
||||
@@ -756,7 +760,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set fontSize(value: number) {
|
||||
set fontSize(value: number | null) {
|
||||
this._fontSize = valueOrDefault(value, this._defaultStyle.fontSize);
|
||||
}
|
||||
|
||||
@@ -765,7 +769,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get fontScaleX(): number {
|
||||
get fontScaleX(): number | null {
|
||||
return this._fontScaleX;
|
||||
}
|
||||
|
||||
@@ -774,7 +778,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set fontScaleX(value: number) {
|
||||
set fontScaleX(value: number | null) {
|
||||
this._fontScaleX = valueOrDefault(value, this._defaultStyle.fontScaleX);
|
||||
}
|
||||
|
||||
@@ -783,7 +787,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get fontScaleY(): number {
|
||||
get fontScaleY(): number | null {
|
||||
return this._fontScaleY;
|
||||
}
|
||||
|
||||
@@ -792,7 +796,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set fontScaleY(value: number) {
|
||||
set fontScaleY(value: number | null) {
|
||||
this._fontScaleY = valueOrDefault(value, this._defaultStyle.fontScaleY);
|
||||
}
|
||||
|
||||
@@ -801,7 +805,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get letterSpacing(): number {
|
||||
get letterSpacing(): number | null {
|
||||
return this._letterSpacing;
|
||||
}
|
||||
|
||||
@@ -810,7 +814,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set letterSpacing(value: number) {
|
||||
set letterSpacing(value: number | null) {
|
||||
this._letterSpacing = valueOrDefault(value, this._defaultStyle.letterSpacing);
|
||||
}
|
||||
|
||||
@@ -819,7 +823,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get rotationX(): number {
|
||||
get rotationX(): number | null {
|
||||
return this._rotationX;
|
||||
}
|
||||
|
||||
@@ -828,8 +832,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set rotationX(value: number) {
|
||||
this._rotationX = valueOrDefault<number>(value, 0);
|
||||
set rotationX(value: number | null) {
|
||||
this._rotationX = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -837,7 +841,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get rotationY(): number {
|
||||
get rotationY(): number | null {
|
||||
return this._rotationY;
|
||||
}
|
||||
|
||||
@@ -846,8 +850,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set rotationY(value: number) {
|
||||
this._rotationY = valueOrDefault<number>(value, 0);
|
||||
set rotationY(value: number | null) {
|
||||
this._rotationY = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -855,7 +859,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get rotationZ(): number {
|
||||
get rotationZ(): number | null {
|
||||
return this._rotationZ;
|
||||
}
|
||||
|
||||
@@ -864,7 +868,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set rotationZ(value: number) {
|
||||
set rotationZ(value: number | null) {
|
||||
this._rotationZ = valueOrDefault(value, this._defaultStyle.rotationZ);
|
||||
}
|
||||
|
||||
@@ -873,7 +877,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get skewX(): number {
|
||||
get skewX(): number | null {
|
||||
return this._skewX;
|
||||
}
|
||||
|
||||
@@ -882,8 +886,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set skewX(value: number) {
|
||||
this._skewX = valueOrDefault<number>(value, 0);
|
||||
set skewX(value: number | null) {
|
||||
this._skewX = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -891,7 +895,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get skewY(): number {
|
||||
get skewY(): number | null {
|
||||
return this._skewY;
|
||||
}
|
||||
|
||||
@@ -900,8 +904,8 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set skewY(value: number) {
|
||||
this._skewY = valueOrDefault<number>(value, 0);
|
||||
set skewY(value: number | null) {
|
||||
this._skewY = valueOrDefault(value, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -909,7 +913,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {!libjass.Color}
|
||||
*/
|
||||
get primaryColor(): Color {
|
||||
get primaryColor(): Color | null {
|
||||
return this._primaryColor;
|
||||
}
|
||||
|
||||
@@ -918,7 +922,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {libjass.Color}
|
||||
*/
|
||||
set primaryColor(value: Color) {
|
||||
set primaryColor(value: Color | null) {
|
||||
this._primaryColor = valueOrDefault(value, this._defaultStyle.primaryColor);
|
||||
}
|
||||
|
||||
@@ -927,7 +931,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {!libjass.Color}
|
||||
*/
|
||||
get secondaryColor(): Color {
|
||||
get secondaryColor(): Color | null {
|
||||
return this._secondaryColor;
|
||||
}
|
||||
|
||||
@@ -936,7 +940,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {libjass.Color}
|
||||
*/
|
||||
set secondaryColor(value: Color) {
|
||||
set secondaryColor(value: Color | null) {
|
||||
this._secondaryColor = valueOrDefault(value, this._defaultStyle.secondaryColor);
|
||||
}
|
||||
|
||||
@@ -945,7 +949,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {!libjass.Color}
|
||||
*/
|
||||
get outlineColor(): Color {
|
||||
get outlineColor(): Color | null {
|
||||
return this._outlineColor;
|
||||
}
|
||||
|
||||
@@ -954,7 +958,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {libjass.Color}
|
||||
*/
|
||||
set outlineColor(value: Color) {
|
||||
set outlineColor(value: Color | null) {
|
||||
this._outlineColor = valueOrDefault(value, this._defaultStyle.outlineColor);
|
||||
}
|
||||
|
||||
@@ -963,7 +967,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {!libjass.Color}
|
||||
*/
|
||||
get shadowColor(): Color {
|
||||
get shadowColor(): Color | null {
|
||||
return this._shadowColor;
|
||||
}
|
||||
|
||||
@@ -972,7 +976,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {libjass.Color}
|
||||
*/
|
||||
set shadowColor(value: Color) {
|
||||
set shadowColor(value: Color | null) {
|
||||
this._shadowColor = valueOrDefault(value, this._defaultStyle.shadowColor);
|
||||
}
|
||||
|
||||
@@ -981,7 +985,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get primaryAlpha(): number {
|
||||
get primaryAlpha(): number | null {
|
||||
return this._primaryAlpha;
|
||||
}
|
||||
|
||||
@@ -990,7 +994,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set primaryAlpha(value: number) {
|
||||
set primaryAlpha(value: number | null) {
|
||||
this._primaryAlpha = valueOrDefault(value, this._defaultStyle.primaryColor.alpha);
|
||||
}
|
||||
|
||||
@@ -999,7 +1003,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get secondaryAlpha(): number {
|
||||
get secondaryAlpha(): number | null {
|
||||
return this._secondaryAlpha;
|
||||
}
|
||||
|
||||
@@ -1008,7 +1012,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set secondaryAlpha(value: number) {
|
||||
set secondaryAlpha(value: number | null) {
|
||||
this._secondaryAlpha = valueOrDefault(value, this._defaultStyle.secondaryColor.alpha);
|
||||
}
|
||||
|
||||
@@ -1017,7 +1021,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get outlineAlpha(): number {
|
||||
get outlineAlpha(): number | null {
|
||||
return this._outlineAlpha;
|
||||
}
|
||||
|
||||
@@ -1026,7 +1030,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set outlineAlpha(value: number) {
|
||||
set outlineAlpha(value: number | null) {
|
||||
this._outlineAlpha = valueOrDefault(value, this._defaultStyle.outlineColor.alpha);
|
||||
}
|
||||
|
||||
@@ -1035,7 +1039,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {number}
|
||||
*/
|
||||
get shadowAlpha(): number {
|
||||
get shadowAlpha(): number | null {
|
||||
return this._shadowAlpha;
|
||||
}
|
||||
|
||||
@@ -1044,7 +1048,7 @@ export class SpanStyles {
|
||||
*
|
||||
* @type {?number}
|
||||
*/
|
||||
set shadowAlpha(value: number) {
|
||||
set shadowAlpha(value: number | null) {
|
||||
this._shadowAlpha = valueOrDefault(value, this._defaultStyle.shadowColor.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* libjass
|
||||
*
|
||||
* https://github.com/Arnavion/libjass
|
||||
*
|
||||
* Copyright 2013 Arnav Singh
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
interface Node {
|
||||
cloneNode(deep?: boolean): this;
|
||||
}
|
||||
|
||||
interface SVGFEComponentTransferElement {
|
||||
appendChild(newChild: SVGFEFuncAElement): SVGFEFuncAElement;
|
||||
appendChild(newChild: SVGFEFuncBElement): SVGFEFuncBElement;
|
||||
appendChild(newChild: SVGFEFuncGElement): SVGFEFuncGElement;
|
||||
appendChild(newChild: SVGFEFuncRElement): SVGFEFuncRElement;
|
||||
}
|
||||
|
||||
interface SVGFEMergeElement {
|
||||
appendChild(newChild: SVGFEMergeNodeElement): SVGFEMergeNodeElement;
|
||||
}
|
||||
@@ -20,14 +20,14 @@
|
||||
|
||||
import { Map } from "./utility/map";
|
||||
|
||||
const classes = new Map<number, Function & { fromJSON?(obj: any): any }>();
|
||||
const classes = new Map<number, Function & { fromJSON?: (obj: any) => any }>();
|
||||
|
||||
/**
|
||||
* Registers a class as a serializable type.
|
||||
*
|
||||
* @param {function(new:*)} clazz
|
||||
*/
|
||||
export function registerClass(clazz: Function & { fromJSON?(obj: any): any }): void {
|
||||
export function registerClass(clazz: Function & { fromJSON?: (obj: any) => any }): void {
|
||||
clazz.prototype._classTag = classes.size;
|
||||
classes.set(clazz.prototype._classTag, clazz);
|
||||
}
|
||||
@@ -39,7 +39,7 @@ export function registerClass(clazz: Function & { fromJSON?(obj: any): any }): v
|
||||
* @return {string}
|
||||
*/
|
||||
export function serialize(obj: any): string {
|
||||
return JSON.stringify(obj, (/* ujs:unreferenced */ _key: string, value: any) => {
|
||||
return JSON.stringify(obj, (/* ujs:unreferenced */ key: string, value: any) => {
|
||||
if (value && (value._classTag !== undefined) && !Object.prototype.hasOwnProperty.call(value, "_classTag")) {
|
||||
// Copy the _classTag from this object's prototype to itself, so that it will be serialized.
|
||||
value._classTag = value._classTag;
|
||||
@@ -54,7 +54,7 @@ export function serialize(obj: any): string {
|
||||
* @return {*}
|
||||
*/
|
||||
export function deserialize(str: string): any {
|
||||
return JSON.parse(str, (/* ujs:unreferenced */ _key: string, value: any) => {
|
||||
return JSON.parse(str, (/* ujs:unreferenced */ key: string, value: any) => {
|
||||
if (value && (value._classTag !== undefined)) {
|
||||
const clazz = classes.get(value._classTag);
|
||||
if (clazz === undefined) {
|
||||
|
||||
+1
-2
@@ -18,7 +18,6 @@
|
||||
"outFile": "../lib/libjass.js",
|
||||
"noImplicitUseStrict": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"types": []
|
||||
"inlineSources": true
|
||||
}
|
||||
}
|
||||
|
||||
-164
@@ -1,164 +0,0 @@
|
||||
{
|
||||
"$schema": "http://json.schemastore.org/tslint",
|
||||
"rules": {
|
||||
"adjacent-overload-signatures": true,
|
||||
"ban-types": false,
|
||||
"member-access": false,
|
||||
"member-ordering": [true, { "order": [
|
||||
"public-static-field",
|
||||
"public-static-method",
|
||||
|
||||
"protected-static-field",
|
||||
"protected-static-method",
|
||||
|
||||
"private-static-field",
|
||||
"private-static-method",
|
||||
|
||||
"public-instance-field",
|
||||
"protected-instance-field",
|
||||
"private-instance-field",
|
||||
|
||||
"public-constructor",
|
||||
"public-instance-method",
|
||||
|
||||
"protected-constructor",
|
||||
"protected-instance-method",
|
||||
|
||||
"private-constructor",
|
||||
"private-instance-method"
|
||||
]}],
|
||||
"no-any": false,
|
||||
"no-empty-interface": false,
|
||||
"no-import-side-effect": true,
|
||||
"no-inferrable-types": false,
|
||||
"no-internal-module": true,
|
||||
"no-magic-numbers": false,
|
||||
"no-namespace": true,
|
||||
"no-non-null-assertion": false,
|
||||
"no-reference": true,
|
||||
"no-var-requires": true,
|
||||
"only-arrow-functions": false,
|
||||
"prefer-for-of": true,
|
||||
"promise-function-async": false,
|
||||
"typedef": [true, "call-signature", "parameter", "property-declaration", "member-variable-declaration"],
|
||||
"typedef-whitespace": [true, {
|
||||
"call-signature": "nospace",
|
||||
"index-signature": "nospace",
|
||||
"parameter": "nospace",
|
||||
"property-declaration": "nospace",
|
||||
"variable-declaration": "nospace"
|
||||
}, {
|
||||
"call-signature": "space",
|
||||
"index-signature": "space",
|
||||
"parameter": "space",
|
||||
"property-declaration": "space",
|
||||
"variable-declaration": "space"
|
||||
}],
|
||||
"unified-signatures": true,
|
||||
|
||||
"await-promise": true,
|
||||
"ban": false,
|
||||
"curly": true,
|
||||
"forin": true,
|
||||
"import-blacklist": false,
|
||||
"label-position": true,
|
||||
"no-arg": true,
|
||||
"no-bitwise": true,
|
||||
"no-conditional-assignment": true,
|
||||
"no-console": false,
|
||||
"no-construct": true,
|
||||
"no-debugger": true,
|
||||
"no-duplicate-super": true,
|
||||
"no-duplicate-variable": true,
|
||||
"no-empty": false,
|
||||
"no-eval": true,
|
||||
"no-floating-promises": true,
|
||||
"no-for-in-array": true,
|
||||
"no-inferred-empty-object-type": true,
|
||||
"no-invalid-template-strings": true,
|
||||
"no-invalid-this": false,
|
||||
"no-misused-new": true,
|
||||
"no-null-keyword": false,
|
||||
"no-shadowed-variable": false,
|
||||
"no-sparse-arrays": true,
|
||||
"no-string-literal": true,
|
||||
"no-string-throw": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unbound-method": false,
|
||||
"no-unsafe-any": false,
|
||||
"no-unsafe-finally": true,
|
||||
"no-unused-expression": true,
|
||||
"no-unused-variable": [true, "check-parameters"],
|
||||
"no-use-before-declare": false,
|
||||
"no-var-keyword": true,
|
||||
"no-void-expression": [true, "ignore-arrow-function-shorthand"],
|
||||
"radix": false,
|
||||
"restrict-plus-operands": true,
|
||||
"strict-boolean-expressions": false,
|
||||
"strict-type-predicates": true,
|
||||
"switch-default": false,
|
||||
"triple-equals": true,
|
||||
"typeof-compare": true,
|
||||
"use-isnan": true,
|
||||
|
||||
"cyclomatic-complexity": false,
|
||||
"eofline": true,
|
||||
"indent": [true, "tabs"],
|
||||
"linebreak-style": [true, "LF"],
|
||||
"max-classes-per-file": false,
|
||||
"max-file-line-count": false,
|
||||
"max-line-length": false,
|
||||
"no-default-export": true,
|
||||
"no-mergeable-namespace": true,
|
||||
"no-require-imports": true,
|
||||
"object-literal-sort-keys": false,
|
||||
"prefer-const": [true, { "destructuring": "all" }],
|
||||
"trailing-comma": [true, { "multiline": "always", "singleline": "never" }],
|
||||
|
||||
"align": [true, "statements"],
|
||||
"array-type": [true, "array"],
|
||||
"arrow-parens": [true, "ban-single-arg-parens"],
|
||||
"arrow-return-shorthand": true,
|
||||
"callable-types": true,
|
||||
"class-name": true,
|
||||
"comment-format": [true, "check-space"],
|
||||
"completed-docs": false,
|
||||
"file-header": ["true", "Copyright \\d{4}"],
|
||||
"import-spacing": true,
|
||||
"interface-name": [true, "never-prefix"],
|
||||
"interface-over-type-literal": false,
|
||||
"jsdoc-format": true,
|
||||
"match-default-export-name": true,
|
||||
"newline-before-return": false,
|
||||
"new-parens": true,
|
||||
"no-angle-bracket-type-assertion": true,
|
||||
"no-boolean-literal-compare": true,
|
||||
"no-consecutive-blank-lines": true,
|
||||
"no-parameter-properties": false,
|
||||
"no-reference-import": true,
|
||||
"no-trailing-whitespace": true,
|
||||
"no-unnecessary-callback-wrapper": true,
|
||||
"no-unnecessary-initializer": true,
|
||||
"no-unnecessary-qualifier": true,
|
||||
"object-literal-key-quotes": [true, "as-needed"],
|
||||
"object-literal-shorthand": true,
|
||||
"one-line": [true, "check-open-brace", "check-whitespace"],
|
||||
"one-variable-per-declaration": true,
|
||||
"ordered-imports": [true, { "import-sources-order": "case-insensitive", "named-imports-order": "case-insensitive" }],
|
||||
"prefer-function-over-method": [true, "allow-public", "allow-protected"],
|
||||
"prefer-method-signature": true,
|
||||
"prefer-template": [true, "allow-single-concat"],
|
||||
"quotemark": [true, "double", "avoid-escape"],
|
||||
"return-undefined": true,
|
||||
"space-before-function-paren": [true, {
|
||||
"anonymous": "always",
|
||||
"named": "never",
|
||||
"asyncArrow": "always",
|
||||
"method": "never",
|
||||
"constructor": "never"
|
||||
}],
|
||||
"semicolon": [true, "always"],
|
||||
"variable-name": [true, "ban-keywords", "check-format", "allow-leading-underscore"],
|
||||
"whitespace": [true, "check-branch", "check-decl", "check-operator", "check-module", "check-separator", "check-type", "check-typecast", "check-preblock"]
|
||||
}
|
||||
}
|
||||
+133
-122
@@ -18,132 +18,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { parseLineIntoTypedTemplate } from "../parser/misc";
|
||||
import { SrtStreamParser, StreamParser } from "../parser/stream-parsers";
|
||||
import { BrowserReadableStream, Stream, StringStream, XhrStream } from "../parser/streams";
|
||||
import { Attachment } from "./attachment";
|
||||
import { Dialogue } from "./dialogue";
|
||||
import { Style } from "./style";
|
||||
import { ScriptProperties } from "./script-properties";
|
||||
|
||||
import { registerClass as serializable } from "../serialization";
|
||||
import { Format } from "./misc";
|
||||
|
||||
import { debugMode, verboseMode } from "../settings";
|
||||
|
||||
import * as parser from "../parser";
|
||||
import { parseLineIntoTypedTemplate } from "../parser/misc";
|
||||
import { ReadableStream, TextDecoderConstructor } from "../parser/streams";
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
import { Promise } from "../utility/promise";
|
||||
|
||||
import { Attachment } from "./attachment";
|
||||
import { Dialogue } from "./dialogue";
|
||||
import { Format } from "./misc";
|
||||
import { ScriptProperties } from "./script-properties";
|
||||
import { Style } from "./style";
|
||||
import { registerClass as serializable } from "../serialization";
|
||||
|
||||
declare const global: {
|
||||
fetch?(url: string): Promise<{ body: ReadableStream; ok?: boolean; status?: number; }>;
|
||||
ReadableStream?: Function & { prototype: ReadableStream; };
|
||||
TextDecoder?: TextDecoderConstructor;
|
||||
};
|
||||
|
||||
/**
|
||||
* This class represents an ASS script. It contains the {@link libjass.ScriptProperties}, an array of {@link libjass.Style}s, and an array of {@link libjass.Dialogue}s.
|
||||
*/
|
||||
@serializable
|
||||
export class ASS {
|
||||
/**
|
||||
* Creates an ASS object from the raw text of an ASS script.
|
||||
*
|
||||
* @param {string} raw The raw text of the script.
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>}
|
||||
*/
|
||||
static fromString(raw: string, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
return ASS.fromStream(new StringStream(raw), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given {@link libjass.parser.Stream}.
|
||||
*
|
||||
* @param {!libjass.parser.Stream} stream The stream to parse the script from
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromStream(stream: Stream, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
switch (type) {
|
||||
case Format.ASS:
|
||||
case "ass":
|
||||
return new StreamParser(stream).ass;
|
||||
case Format.SRT:
|
||||
case "srt":
|
||||
return new SrtStreamParser(stream).ass;
|
||||
default:
|
||||
throw new Error(`Invalid value of type: ${ type }`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given URL.
|
||||
*
|
||||
* @param {string} url The URL of the script.
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromUrl(url: string, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
let fetchPromise: Promise<ASS>;
|
||||
|
||||
if (typeof global.fetch === "function" && BrowserReadableStream.isSupported()) {
|
||||
fetchPromise = global.fetch(url).then(response => {
|
||||
if (response.ok === false || (response.ok === undefined && (response.status === undefined || response.status < 200 || response.status > 299))) {
|
||||
throw new Error(`HTTP request for ${ url } failed with status code ${ response.status }`);
|
||||
}
|
||||
|
||||
return ASS.fromReadableStream(response.body, "utf-8", type);
|
||||
});
|
||||
}
|
||||
else {
|
||||
fetchPromise = Promise.reject<ASS>(new Error("Not supported."));
|
||||
}
|
||||
|
||||
return fetchPromise.catch(reason => {
|
||||
if (debugMode) {
|
||||
console.log("fetch() failed, falling back to XHR: %o", reason);
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
const result = ASS.fromStream(new XhrStream(xhr), type);
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given ReadableStream.
|
||||
*
|
||||
* @param {!ReadableStream} stream
|
||||
* @param {string="utf-8"} encoding
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromReadableStream(stream: ReadableStream, encoding: string = "utf-8", type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
return ASS.fromStream(new BrowserReadableStream(stream, encoding), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom deserialization for ASS objects.
|
||||
*
|
||||
* @param {!*} obj
|
||||
* @return {!libjass.ASS}
|
||||
*/
|
||||
static fromJSON(obj: any): ASS {
|
||||
const result: ASS = Object.create(ASS.prototype);
|
||||
|
||||
result._properties = obj._properties;
|
||||
|
||||
result._styles = new Map<string, Style>();
|
||||
for (const name of Object.keys(obj._styles)) {
|
||||
const style = obj._styles[name];
|
||||
result._styles.set(name, style);
|
||||
}
|
||||
|
||||
result._dialogues = obj._dialogues;
|
||||
result._attachments = obj._attachments;
|
||||
result._stylesFormatSpecifier = obj._stylesFormatSpecifier;
|
||||
result._dialoguesFormatSpecifier = obj._dialoguesFormatSpecifier;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private _properties: ScriptProperties = new ScriptProperties();
|
||||
private _styles: Map<string, Style> = new Map<string, Style>();
|
||||
private _dialogues: Dialogue[] = [];
|
||||
@@ -197,15 +100,6 @@ export class ASS {
|
||||
return this._stylesFormatSpecifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* The format specifier for the events section.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
set stylesFormatSpecifier(value: string[] | null) {
|
||||
this._stylesFormatSpecifier = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The format specifier for the styles section.
|
||||
*
|
||||
@@ -215,6 +109,15 @@ export class ASS {
|
||||
return this._dialoguesFormatSpecifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* The format specifier for the events section.
|
||||
*
|
||||
* @type {Array.<string>}
|
||||
*/
|
||||
set stylesFormatSpecifier(value: string[] | null) {
|
||||
this._stylesFormatSpecifier = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* The format specifier for the events section.
|
||||
*
|
||||
@@ -319,4 +222,112 @@ export class ASS {
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the raw text of an ASS script.
|
||||
*
|
||||
* @param {string} raw The raw text of the script.
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>}
|
||||
*/
|
||||
static fromString(raw: string, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
return ASS.fromStream(new parser.StringStream(raw), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given {@link libjass.parser.Stream}.
|
||||
*
|
||||
* @param {!libjass.parser.Stream} stream The stream to parse the script from
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromStream(stream: parser.Stream, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
switch (type) {
|
||||
case Format.ASS:
|
||||
case "ass":
|
||||
return new parser.StreamParser(stream).ass;
|
||||
case Format.SRT:
|
||||
case "srt":
|
||||
return new parser.SrtStreamParser(stream).ass;
|
||||
default:
|
||||
throw new Error(`Invalid value of type: ${ type }`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given URL.
|
||||
*
|
||||
* @param {string} url The URL of the script.
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromUrl(url: string, type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
let fetchPromise: Promise<ASS>;
|
||||
|
||||
if (
|
||||
typeof global.fetch === "function" &&
|
||||
typeof global.ReadableStream === "function" && typeof global.ReadableStream.prototype.getReader === "function" &&
|
||||
typeof global.TextDecoder === "function"
|
||||
) {
|
||||
fetchPromise = global.fetch(url).then(response => {
|
||||
if (response.ok === false || (response.ok === undefined && (response.status < 200 || response.status > 299))) {
|
||||
throw new Error(`HTTP request for ${ url } failed with status code ${ response.status }`);
|
||||
}
|
||||
|
||||
return ASS.fromReadableStream(response.body, "utf-8", type);
|
||||
});
|
||||
}
|
||||
else {
|
||||
fetchPromise = Promise.reject<ASS>(new Error("Not supported."));
|
||||
}
|
||||
|
||||
return fetchPromise.catch(reason => {
|
||||
if (debugMode) {
|
||||
console.log("fetch() failed, falling back to XHR: %o", reason);
|
||||
}
|
||||
|
||||
const xhr = new XMLHttpRequest();
|
||||
const result = ASS.fromStream(new parser.XhrStream(xhr), type);
|
||||
xhr.open("GET", url, true);
|
||||
xhr.send();
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an ASS object from the given ReadableStream.
|
||||
*
|
||||
* @param {!ReadableStream} stream
|
||||
* @param {string="utf-8"} encoding
|
||||
* @param {(number|string)=0} type The type of the script. One of the {@link libjass.Format} constants, or one of the strings "ass" and "srt".
|
||||
* @return {!Promise.<!libjass.ASS>} A promise that will be resolved with the ASS object when it has been fully parsed
|
||||
*/
|
||||
static fromReadableStream(stream: ReadableStream, encoding: string = "utf-8", type: Format | "ass" | "srt" = Format.ASS): Promise<ASS> {
|
||||
return ASS.fromStream(new parser.BrowserReadableStream(stream, encoding), type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom deserialization for ASS objects.
|
||||
*
|
||||
* @param {!*} obj
|
||||
* @return {!libjass.ASS}
|
||||
*/
|
||||
static fromJSON(obj: any): ASS {
|
||||
const result: ASS = Object.create(ASS.prototype);
|
||||
|
||||
result._properties = obj._properties;
|
||||
|
||||
result._styles = new Map<string, Style>();
|
||||
for (const name of Object.keys(obj._styles)) {
|
||||
const style = obj._styles[name];
|
||||
result._styles.set(name, style);
|
||||
}
|
||||
|
||||
result._dialogues = obj._dialogues;
|
||||
result._attachments = obj._attachments;
|
||||
result._stylesFormatSpecifier = obj._stylesFormatSpecifier;
|
||||
result._dialoguesFormatSpecifier = obj._dialoguesFormatSpecifier;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ import { Map } from "../utility/map";
|
||||
*/
|
||||
@serializable
|
||||
export class Dialogue {
|
||||
private static _lastDialogueId: number = -1;
|
||||
private static _lastDialogueId = -1;
|
||||
|
||||
private _id: number;
|
||||
|
||||
@@ -224,7 +224,7 @@ export class Dialogue {
|
||||
this._parts![index] =
|
||||
new parts.Move(
|
||||
part.x1, part.y1, part.x2, part.y2,
|
||||
0, this._end - this._start,
|
||||
0, this._end - this._start
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -235,7 +235,7 @@ export class Dialogue {
|
||||
(part.start === null) ? 0 : part.start,
|
||||
(part.end === null) ? (this._end - this._start) : part.end,
|
||||
(part.accel === null) ? 1 : part.accel,
|
||||
part.tags,
|
||||
part.tags
|
||||
);
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ ${ this._rawPartsString }
|
||||
was parsed as
|
||||
${ this.toString() }
|
||||
The possibly incorrect parses are:
|
||||
${ possiblyIncorrectParses.join("\n") }`,
|
||||
${ possiblyIncorrectParses.join("\n") }`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
|
||||
/**
|
||||
* The format of the string passed to {@link libjass.ASS.fromString}
|
||||
*/
|
||||
|
||||
+2
-2
@@ -18,6 +18,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { valueOrDefault, BorderStyle } from "./misc";
|
||||
|
||||
import { parse } from "../parser/parse";
|
||||
|
||||
import { Color } from "../parts";
|
||||
@@ -26,8 +28,6 @@ import { registerClass as serializable } from "../serialization";
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
|
||||
import { BorderStyle, valueOrDefault } from "./misc";
|
||||
|
||||
/**
|
||||
* This class represents a single global style declaration in a {@link libjass.ASS} script. The styles can be obtained via the {@link libjass.ASS.styles} property.
|
||||
*
|
||||
|
||||
+79
-48
@@ -18,6 +18,48 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface Map<K, V> {
|
||||
/**
|
||||
* @param {K} key
|
||||
* @return {?V}
|
||||
*/
|
||||
get(key: K): V | undefined;
|
||||
|
||||
/**
|
||||
* @param {K} key
|
||||
* @return {boolean}
|
||||
*/
|
||||
has(key: K): boolean;
|
||||
|
||||
/**
|
||||
* @param {K} key
|
||||
* @param {V} value
|
||||
* @return {libjass.Map.<K, V>} This map
|
||||
*/
|
||||
set(key: K, value: V): this;
|
||||
|
||||
/**
|
||||
* @param {K} key
|
||||
* @return {boolean} true if the key was present before being deleted, false otherwise
|
||||
*/
|
||||
delete(key: K): boolean;
|
||||
|
||||
/**
|
||||
*/
|
||||
clear(): void;
|
||||
|
||||
/**
|
||||
* @param {function(V, K, libjass.Map.<K, V>)} callbackfn A function that is called with each key and value in the map.
|
||||
* @param {*} thisArg
|
||||
*/
|
||||
forEach(callbackfn: (value: V, index: K, map: this) => void, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Map implementation for browsers that don't support it. Only supports keys which are of Number or String type, or which have a property called "id".
|
||||
*
|
||||
@@ -51,7 +93,7 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
* @return {?V}
|
||||
*/
|
||||
get(key: K): V | undefined {
|
||||
const property = keyToProperty(key);
|
||||
const property = this._keyToProperty(key);
|
||||
|
||||
if (property === null) {
|
||||
return undefined;
|
||||
@@ -65,7 +107,7 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
* @return {boolean}
|
||||
*/
|
||||
has(key: K): boolean {
|
||||
const property = keyToProperty(key);
|
||||
const property = this._keyToProperty(key);
|
||||
|
||||
if (property === null) {
|
||||
return false;
|
||||
@@ -80,7 +122,7 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
* @return {libjass.Map.<K, V>} This map
|
||||
*/
|
||||
set(key: K, value: V): this {
|
||||
const property = keyToProperty(key);
|
||||
const property = this._keyToProperty(key);
|
||||
|
||||
if (property === null) {
|
||||
throw new Error("This Map implementation only supports Number and String keys, or keys with an id property.");
|
||||
@@ -101,7 +143,7 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
* @return {boolean} true if the key was present before being deleted, false otherwise
|
||||
*/
|
||||
delete(key: K): boolean {
|
||||
const property = keyToProperty(key);
|
||||
const property = this._keyToProperty(key);
|
||||
|
||||
if (property === null) {
|
||||
return false;
|
||||
@@ -142,9 +184,29 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable:variable-name */
|
||||
/**
|
||||
* Converts the given key into a property name for the internal map.
|
||||
*
|
||||
* @param {K} key
|
||||
* @return {?string}
|
||||
*/
|
||||
private _keyToProperty(key: K): string | null {
|
||||
if (typeof key === "number") {
|
||||
return `#${ key }`;
|
||||
}
|
||||
|
||||
if (typeof key === "string") {
|
||||
return `'${ key }`;
|
||||
}
|
||||
|
||||
if ((key as any).id !== undefined) {
|
||||
return `!${ (key as any).id }`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the global implementation of Map if the environment has one, else set to {@link ./utility/map.SimpleMap}
|
||||
@@ -155,34 +217,25 @@ class SimpleMap<K, V> implements Map<K, V> {
|
||||
*
|
||||
* @type {function(new:Map, !Array.<!Array.<*>>=)}
|
||||
*/
|
||||
export let Map: {
|
||||
export var Map: {
|
||||
new <K, V>(iterable?: [K, V][]): Map<K, V>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Map<any, any>;
|
||||
} = (() => {
|
||||
const globalMap = global.Map;
|
||||
|
||||
if (globalMap === undefined) {
|
||||
return SimpleMap;
|
||||
}
|
||||
|
||||
if (typeof globalMap.prototype.forEach !== "function") {
|
||||
return SimpleMap;
|
||||
}
|
||||
} = global.Map || SimpleMap;
|
||||
|
||||
if (typeof Map.prototype.forEach !== "function" || (() => {
|
||||
try {
|
||||
if (new globalMap([[1, "foo"], [2, "bar"]]).size !== 2) {
|
||||
return SimpleMap;
|
||||
}
|
||||
return new Map([[1, "foo"], [2, "bar"]]).size !== 2;
|
||||
}
|
||||
catch (ex) {
|
||||
return SimpleMap;
|
||||
return true;
|
||||
}
|
||||
})()) {
|
||||
Map = SimpleMap;
|
||||
}
|
||||
|
||||
return globalMap as any;
|
||||
})();
|
||||
|
||||
/* tslint:enable:variable-name */
|
||||
declare var global: {
|
||||
Map?: typeof Map;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the Map implementation used by libjass to the provided one. If null, {@link ./utility/map.SimpleMap} is used.
|
||||
@@ -197,25 +250,3 @@ export function setImplementation(value: typeof Map | null): void {
|
||||
Map = SimpleMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given key into a property name for the internal map.
|
||||
*
|
||||
* @param {*} key
|
||||
* @return {?string}
|
||||
*/
|
||||
function keyToProperty(key: any): string | null {
|
||||
if (typeof key === "number") {
|
||||
return `#${ key }`;
|
||||
}
|
||||
|
||||
if (typeof key === "string") {
|
||||
return `'${ key }`;
|
||||
}
|
||||
|
||||
if ((key as any).id !== undefined) {
|
||||
return `!${ (key as any).id }`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
+170
-132
@@ -18,15 +18,45 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
// Based on https://github.com/petkaantonov/bluebird/blob/1b1467b95442c12378d0ea280ede61d640ab5510/src/schedule.js
|
||||
const enqueueJob = (function (): (callback: () => void) => void {
|
||||
/* tslint:disable-next-line:variable-name */
|
||||
const MutationObserver = global.MutationObserver || global.WebkitMutationObserver;
|
||||
export interface Thenable<T> {
|
||||
/** @type {function(this:!Thenable.<T>, function(T|!Thenable.<T>), function(*))} */
|
||||
then: ThenableThen<T>;
|
||||
}
|
||||
|
||||
export interface ThenableThen<T> {
|
||||
/** @type {function(this:!Thenable.<T>, function(T|!Thenable.<T>), function(*))} */
|
||||
(this: Thenable<T>, resolve: ((resolution: T | Thenable<T>) => void) | undefined, reject: ((reason: any) => void) | undefined): void;
|
||||
}
|
||||
|
||||
export interface Promise<T> extends Thenable<T> {
|
||||
/**
|
||||
* @param {function(T):!Thenable.<U>} onFulfilled
|
||||
* @param {?function(*):(U|!Thenable.<U>)} onRejected
|
||||
* @return {!Promise.<U>}
|
||||
*/
|
||||
then<U>(onFulfilled: (value: T) => Thenable<U> | undefined, onRejected?: (reason: any) => U | Thenable<U>): Promise<U>;
|
||||
|
||||
/**
|
||||
* @param {function(T):U} onFulfilled
|
||||
* @param {?function(*):(U|!Thenable.<U>)} onRejected
|
||||
* @return {!Promise.<U>}
|
||||
*/
|
||||
then<U>(onFulfilled: (value: T) => U | undefined, onRejected?: (reason: any) => U | Thenable<U>): Promise<U>;
|
||||
|
||||
/**
|
||||
* @param {function(*):(T|!Thenable.<T>)} onRejected
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
catch(onRejected: (reason: any) => T | Thenable<T>): Promise<T>;
|
||||
}
|
||||
|
||||
// Based on https://github.com/petkaantonov/bluebird/blob/1b1467b95442c12378d0ea280ede61d640ab5510/src/schedule.js
|
||||
const enqueueJob: (callback: () => void) => void = (function () {
|
||||
const MutationObserver = global.MutationObserver || global.WebkitMutationObserver;
|
||||
if (global.process !== undefined && typeof global.process.nextTick === "function") {
|
||||
const nextTick = global.process.nextTick;
|
||||
const process = global.process;
|
||||
return (callback: () => void) => {
|
||||
nextTick(callback);
|
||||
process.nextTick(callback);
|
||||
};
|
||||
}
|
||||
else if (MutationObserver !== undefined) {
|
||||
@@ -72,70 +102,15 @@ const enqueueJob = (function (): (callback: () => void) => void {
|
||||
* @param {function(function(T|!Thenable.<T>), function(*))} executor
|
||||
*/
|
||||
class SimplePromise<T> {
|
||||
/**
|
||||
* @param {T|!Thenable.<T>} value
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static resolve<T>(value: T | Thenable<T>): Promise<T> {
|
||||
if (value instanceof SimplePromise) {
|
||||
return value;
|
||||
}
|
||||
private _state: SimplePromiseState = SimplePromiseState.PENDING;
|
||||
|
||||
return new Promise<T>(resolve => resolve(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} reason
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static reject<T>(reason: any): Promise<T> {
|
||||
return new Promise<T>((/* ujs:unreferenced */ _resolve, reject) => reject(reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array.<T|!Thenable.<T>>} values
|
||||
* @return {!Promise.<!Array.<T>>}
|
||||
*/
|
||||
static all<T>(values: (T | Thenable<T>)[]): Promise<T[]> {
|
||||
return new Promise<T[]>((resolve, reject) => {
|
||||
const result: T[] = [];
|
||||
|
||||
let numUnresolved = values.length;
|
||||
if (numUnresolved === 0) {
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
|
||||
values.forEach((value, index) => Promise.resolve(value).then(value => {
|
||||
result[index] = value;
|
||||
numUnresolved--;
|
||||
|
||||
if (numUnresolved === 0) {
|
||||
resolve(result);
|
||||
}
|
||||
}, reject));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array.<T|!Thenable.<T>>} values
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static race<T>(values: (T | Thenable<T>)[]): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
for (const value of values) {
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
Promise.resolve(value).then(resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private _state: SimplePromiseState<T> = { state: "pending" };
|
||||
private _fulfillReactions: FulfilledPromiseReaction<T, any>[] = [];
|
||||
private _rejectReactions: RejectedPromiseReaction<any>[] = [];
|
||||
|
||||
private _fulfilledValue: T | null = null;
|
||||
private _rejectedReason: any = null;
|
||||
|
||||
constructor(executor: (resolve: (resolution: T | Thenable<T>) => void, reject: (reason: any) => void) => void) {
|
||||
/* tslint:disable-next-line:strict-type-predicates */
|
||||
if (typeof executor !== "function") {
|
||||
throw new TypeError(`typeof executor !== "function"`);
|
||||
}
|
||||
@@ -175,18 +150,18 @@ class SimplePromise<T> {
|
||||
handler: onRejected,
|
||||
};
|
||||
|
||||
switch (this._state.state) {
|
||||
case "pending":
|
||||
switch (this._state) {
|
||||
case SimplePromiseState.PENDING:
|
||||
this._fulfillReactions.push(fulfillReaction);
|
||||
this._rejectReactions.push(rejectReaction);
|
||||
break;
|
||||
|
||||
case "fulfilled":
|
||||
enqueueFulfilledReactionJob(fulfillReaction, this._state.value);
|
||||
case SimplePromiseState.FULFILLED:
|
||||
this._enqueueFulfilledReactionJob(fulfillReaction, this._fulfilledValue!);
|
||||
break;
|
||||
|
||||
case "rejected":
|
||||
enqueueRejectedReactionJob(rejectReaction, this._state.reason);
|
||||
case SimplePromiseState.REJECTED:
|
||||
this._enqueueRejectedReactionJob(rejectReaction, this._rejectedReason);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -201,6 +176,63 @@ class SimplePromise<T> {
|
||||
return this.then(undefined, onRejected);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {T|!Thenable.<T>} value
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static resolve<T>(value: T | Thenable<T>): Promise<T> {
|
||||
if (value instanceof SimplePromise) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return new Promise<T>(resolve => resolve(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {*} reason
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static reject<T>(reason: any): Promise<T> {
|
||||
return new Promise<T>((/* ujs:unreferenced */ resolve, reject) => reject(reason));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array.<T|!Thenable.<T>>} values
|
||||
* @return {!Promise.<!Array.<T>>}
|
||||
*/
|
||||
static all<T>(values: (T | Thenable<T>)[]): Promise<T[]> {
|
||||
return new Promise<T[]>((resolve, reject) => {
|
||||
const result: T[] = [];
|
||||
|
||||
let numUnresolved = values.length;
|
||||
if (numUnresolved === 0) {
|
||||
resolve(result);
|
||||
return;
|
||||
}
|
||||
|
||||
values.forEach((value, index) => Promise.resolve(value).then(value => {
|
||||
result[index] = value;
|
||||
numUnresolved--;
|
||||
|
||||
if (numUnresolved === 0) {
|
||||
resolve(result);
|
||||
}
|
||||
}, reject));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Array.<T|!Thenable.<T>>} values
|
||||
* @return {!Promise.<T>}
|
||||
*/
|
||||
static race<T>(values: (T | Thenable<T>)[]): Promise<T> {
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
for (const value of values) {
|
||||
Promise.resolve(value).then(resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {{ resolve(T|!Thenable.<T>), reject(*) }}
|
||||
*/
|
||||
@@ -219,23 +251,19 @@ class SimplePromise<T> {
|
||||
return;
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:strict-type-predicates */
|
||||
if (resolution === null || (typeof resolution !== "object" && typeof resolution !== "function")) {
|
||||
this._fulfill(resolution as T);
|
||||
return;
|
||||
}
|
||||
|
||||
let then: ThenableThen<T>;
|
||||
|
||||
try {
|
||||
then = (resolution as Thenable<T>).then;
|
||||
var then = (resolution as Thenable<T>).then;
|
||||
}
|
||||
catch (ex) {
|
||||
this._reject(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:strict-type-predicates */
|
||||
if (typeof then !== "function") {
|
||||
this._fulfill(resolution as T);
|
||||
return;
|
||||
@@ -278,12 +306,13 @@ class SimplePromise<T> {
|
||||
private _fulfill(value: T): void {
|
||||
const reactions = this._fulfillReactions;
|
||||
|
||||
this._state = { state: "fulfilled", value };
|
||||
this._fulfilledValue = value;
|
||||
this._fulfillReactions = [];
|
||||
this._rejectReactions = [];
|
||||
this._state = SimplePromiseState.FULFILLED;
|
||||
|
||||
for (const reaction of reactions) {
|
||||
enqueueFulfilledReactionJob(reaction, value);
|
||||
this._enqueueFulfilledReactionJob(reaction, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,17 +322,60 @@ class SimplePromise<T> {
|
||||
private _reject(reason: any): void {
|
||||
const reactions = this._rejectReactions;
|
||||
|
||||
this._state = { state: "rejected", reason };
|
||||
this._rejectedReason = reason;
|
||||
this._fulfillReactions = [];
|
||||
this._rejectReactions = [];
|
||||
this._state = SimplePromiseState.REJECTED;
|
||||
|
||||
for (const reaction of reactions) {
|
||||
enqueueRejectedReactionJob(reaction, reason);
|
||||
this._enqueueRejectedReactionJob(reaction, reason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable:variable-name */
|
||||
/**
|
||||
* @param {!FulfilledPromiseReaction.<T, *>} reaction
|
||||
* @param {T} value
|
||||
*/
|
||||
private _enqueueFulfilledReactionJob(reaction: FulfilledPromiseReaction<T, any>, value: T): void {
|
||||
enqueueJob(() => {
|
||||
const { capabilities: { resolve, reject }, handler } = reaction;
|
||||
|
||||
let handlerResult: any | Thenable<any>;
|
||||
|
||||
try {
|
||||
handlerResult = handler(value);
|
||||
}
|
||||
catch (ex) {
|
||||
reject(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(handlerResult);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!RejectedPromiseReaction.<*>} reaction
|
||||
* @param {*} reason
|
||||
*/
|
||||
private _enqueueRejectedReactionJob(reaction: RejectedPromiseReaction<any>, reason: any): void {
|
||||
enqueueJob(() => {
|
||||
const { capabilities: { resolve, reject }, handler } = reaction;
|
||||
|
||||
let handlerResult: any | Thenable<any>;
|
||||
|
||||
try {
|
||||
handlerResult = handler(reason);
|
||||
}
|
||||
catch (ex) {
|
||||
reject(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(handlerResult);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the global implementation of Promise if the environment has one, else set to {@link ./utility/promise.SimplePromise}
|
||||
@@ -314,9 +386,8 @@ class SimplePromise<T> {
|
||||
*
|
||||
* @type {function(new:Promise)}
|
||||
*/
|
||||
export let Promise: {
|
||||
export var Promise: {
|
||||
new <T>(init: (resolve: (value: T | Thenable<T>) => void, reject: (reason: any) => void) => void): Promise<T>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Promise<any>;
|
||||
resolve<T>(value: T | Thenable<T>): Promise<T>;
|
||||
reject<T>(reason: any): Promise<T>;
|
||||
@@ -324,7 +395,14 @@ export let Promise: {
|
||||
race<T>(values: (T | Thenable<T>)[]): Promise<T>;
|
||||
} = global.Promise || SimplePromise;
|
||||
|
||||
/* tslint:enable:variable-name */
|
||||
declare var global: {
|
||||
Promise?: typeof Promise;
|
||||
MutationObserver?: typeof MutationObserver;
|
||||
WebkitMutationObserver?: typeof MutationObserver;
|
||||
process?: {
|
||||
nextTick(callback: () => void): void;
|
||||
}
|
||||
};
|
||||
|
||||
interface FulfilledPromiseReaction<T, U> {
|
||||
/** @type {!libjass.DeferredPromise.<U>} */
|
||||
@@ -351,7 +429,11 @@ interface RejectedPromiseReaction<U> {
|
||||
/**
|
||||
* The state of the {@link ./utility/promise.SimplePromise}
|
||||
*/
|
||||
type SimplePromiseState<T> = { state: "pending" } | { state: "fulfilled"; value: T; } | { state: "rejected"; reason: any; };
|
||||
enum SimplePromiseState {
|
||||
PENDING = 0,
|
||||
FULFILLED = 1,
|
||||
REJECTED = 2,
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the Promise implementation used by libjass to the provided one. If null, {@link ./utility/promise.SimplePromise} is used.
|
||||
@@ -371,6 +453,8 @@ export function setImplementation(value: typeof Promise | null): void {
|
||||
* A deferred promise.
|
||||
*/
|
||||
export class DeferredPromise<T> {
|
||||
private _promise: Promise<T>;
|
||||
|
||||
/**
|
||||
* @type {function(T|!Thenable.<T>)}
|
||||
*/
|
||||
@@ -381,8 +465,6 @@ export class DeferredPromise<T> {
|
||||
*/
|
||||
reject: (reason: any) => void;
|
||||
|
||||
private _promise: Promise<T>;
|
||||
|
||||
constructor() {
|
||||
this._promise = new Promise<T>((resolve, reject) => {
|
||||
Object.defineProperties(this, {
|
||||
@@ -451,47 +533,3 @@ export function lastly<T>(promise: Promise<T>, body: () => void): Promise<T> {
|
||||
throw reason;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!FulfilledPromiseReaction.<T, *>} reaction
|
||||
* @param {T} value
|
||||
*/
|
||||
function enqueueFulfilledReactionJob<T>(reaction: FulfilledPromiseReaction<T, any>, value: T): void {
|
||||
enqueueJob(() => {
|
||||
const { capabilities: { resolve, reject }, handler } = reaction;
|
||||
|
||||
let handlerResult: any | Thenable<any>;
|
||||
|
||||
try {
|
||||
handlerResult = handler(value);
|
||||
}
|
||||
catch (ex) {
|
||||
reject(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(handlerResult);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!RejectedPromiseReaction.<*>} reaction
|
||||
* @param {*} reason
|
||||
*/
|
||||
function enqueueRejectedReactionJob(reaction: RejectedPromiseReaction<any>, reason: any): void {
|
||||
enqueueJob(() => {
|
||||
const { capabilities: { resolve, reject }, handler } = reaction;
|
||||
|
||||
let handlerResult: any | Thenable<any>;
|
||||
|
||||
try {
|
||||
handlerResult = handler(reason);
|
||||
}
|
||||
catch (ex) {
|
||||
reject(ex);
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(handlerResult);
|
||||
});
|
||||
}
|
||||
|
||||
+60
-42
@@ -18,6 +18,35 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export interface Set<T> {
|
||||
/**
|
||||
* @param {T} value
|
||||
* @return {libjass.Set.<T>} This set
|
||||
*/
|
||||
add(value: T): this;
|
||||
|
||||
/**
|
||||
*/
|
||||
clear(): void;
|
||||
|
||||
/**
|
||||
* @param {T} value
|
||||
* @return {boolean}
|
||||
*/
|
||||
has(value: T): boolean;
|
||||
|
||||
/**
|
||||
* @param {function(T, T, libjass.Set.<T>)} callbackfn A function that is called with each value in the set.
|
||||
* @param {*} thisArg
|
||||
*/
|
||||
forEach(callbackfn: (value: T, index: T, set: this) => void, thisArg?: any): void;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
size: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set implementation for browsers that don't support it. Only supports Number and String elements.
|
||||
*
|
||||
@@ -50,7 +79,7 @@ class SimpleSet<T> implements Set<T> {
|
||||
* @return {libjass.Set.<T>} This set
|
||||
*/
|
||||
add(value: T): this {
|
||||
const property = toProperty(value);
|
||||
const property = this._toProperty(value);
|
||||
|
||||
if (property === null) {
|
||||
throw new Error("This Set implementation only supports Number and String values.");
|
||||
@@ -77,7 +106,7 @@ class SimpleSet<T> implements Set<T> {
|
||||
* @return {boolean}
|
||||
*/
|
||||
has(value: T): boolean {
|
||||
const property = toProperty(value);
|
||||
const property = this._toProperty(value);
|
||||
|
||||
if (property === null) {
|
||||
return false;
|
||||
@@ -103,9 +132,25 @@ class SimpleSet<T> implements Set<T> {
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
}
|
||||
|
||||
/* tslint:disable:variable-name */
|
||||
/**
|
||||
* Converts the given value into a property name for the internal map.
|
||||
*
|
||||
* @param {T} value
|
||||
* @return {?string}
|
||||
*/
|
||||
private _toProperty(value: T): string | null {
|
||||
if (typeof value === "number") {
|
||||
return `#${ value }`;
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
return `'${ value }`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set to the global implementation of Set if the environment has one, else set to {@link ./utility/set.SimpleSet}
|
||||
@@ -116,34 +161,25 @@ class SimpleSet<T> implements Set<T> {
|
||||
*
|
||||
* @type {function(new:Set, !Array.<T>=)}
|
||||
*/
|
||||
export let Set: {
|
||||
export var Set: {
|
||||
new <T>(iterable?: T[]): Set<T>;
|
||||
/* tslint:disable-next-line:member-ordering */
|
||||
prototype: Set<any>;
|
||||
} = (() => {
|
||||
const globalSet = global.Set;
|
||||
|
||||
if (globalSet === undefined) {
|
||||
return SimpleSet;
|
||||
}
|
||||
|
||||
if (typeof globalSet.prototype.forEach !== "function") {
|
||||
return SimpleSet;
|
||||
}
|
||||
} = global.Set || SimpleSet;
|
||||
|
||||
if (typeof Set.prototype.forEach !== "function" || (() => {
|
||||
try {
|
||||
if ((new globalSet([1, 2])).size !== 2) {
|
||||
return SimpleSet;
|
||||
}
|
||||
return new Set([1, 2]).size !== 2;
|
||||
}
|
||||
catch (ex) {
|
||||
return SimpleSet;
|
||||
return true;
|
||||
}
|
||||
})()) {
|
||||
Set = SimpleSet;
|
||||
}
|
||||
|
||||
return globalSet as any;
|
||||
})();
|
||||
|
||||
/* tslint:enable:variable-name */
|
||||
declare var global: {
|
||||
Set?: typeof Set;
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets the Set implementation used by libjass to the provided one. If null, {@link ./utility/set.SimpleSet} is used.
|
||||
@@ -158,21 +194,3 @@ export function setImplementation(value: typeof Set | null): void {
|
||||
Set = SimpleSet;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the given value into a property name for the internal map.
|
||||
*
|
||||
* @param {*} value
|
||||
* @return {?string}
|
||||
*/
|
||||
function toProperty(value: any): string | null {
|
||||
if (typeof value === "number") {
|
||||
return `#${ value }`;
|
||||
}
|
||||
|
||||
if (typeof value === "string") {
|
||||
return `'${ value }`;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -18,11 +18,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { deserialize, serialize } from "../serialization";
|
||||
import { serialize, deserialize } from "../serialization";
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
|
||||
import { DeferredPromise, Promise } from "../utility/promise";
|
||||
import { Promise, DeferredPromise } from "../utility/promise";
|
||||
|
||||
import { WorkerCommands } from "./commands";
|
||||
import { getWorkerCommandHandler, registerWorkerCommand } from "./misc";
|
||||
@@ -44,7 +44,33 @@ export interface WorkerChannel {
|
||||
/**
|
||||
* The signature of a handler registered to handle a particular command in {@link libjass.webworker.WorkerCommands}
|
||||
*/
|
||||
export type WorkerCommandHandler = (parameters: any) => Promise<any>;
|
||||
export interface WorkerCommandHandler {
|
||||
(parameters: any): Promise<any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface implemented by a communication channel to the other side.
|
||||
*/
|
||||
export interface WorkerCommunication {
|
||||
/**
|
||||
* @param {"message"} type
|
||||
* @param {function(!MessageEvent): *} listener
|
||||
* @param {?boolean} useCapture
|
||||
*/
|
||||
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {!EventListener} listener
|
||||
* @param {?boolean} useCapture
|
||||
*/
|
||||
addEventListener(type: string, listener: EventListener, useCapture?: boolean): void;
|
||||
|
||||
/**
|
||||
* @param {*} message
|
||||
*/
|
||||
postMessage(message: any): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The interface implemented by a request sent to the other side of the communication channel.
|
||||
@@ -107,7 +133,7 @@ interface WorkerResponseMessage {
|
||||
export class WorkerChannelImpl implements WorkerChannel {
|
||||
private static _lastRequestId: number = -1;
|
||||
|
||||
private _pendingRequests: Map<number, DeferredPromise<any>> = new Map<number, DeferredPromise<any>>();
|
||||
private _pendingRequests = new Map<number, DeferredPromise<any>>();
|
||||
|
||||
constructor(private _comm: WorkerCommunication) {
|
||||
this._comm.addEventListener("message", ev => this._onMessage(ev.data as string), false);
|
||||
@@ -183,13 +209,12 @@ export class WorkerChannelImpl implements WorkerChannel {
|
||||
return;
|
||||
}
|
||||
|
||||
/* tslint:disable-next-line:no-floating-promises */
|
||||
commandCallback(requestMessage.parameters).then<WorkerResponseMessage>(
|
||||
result => ({ requestId, error: null, result }),
|
||||
error => ({ requestId, error, result: null }),
|
||||
error => ({ requestId, error, result: null })
|
||||
).then(responseMessage => this._respond(responseMessage));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
registerWorkerCommand(WorkerCommands.Ping, () => Promise.resolve(null));
|
||||
registerWorkerCommand(WorkerCommands.Ping, parameters => Promise.resolve(null));
|
||||
|
||||
@@ -28,9 +28,9 @@ export { WorkerCommands } from "./commands";
|
||||
*
|
||||
* @type {boolean}
|
||||
*/
|
||||
export const supported = global.Worker !== undefined;
|
||||
export const supported = typeof Worker !== "undefined";
|
||||
|
||||
const _scriptNode = (global.document !== undefined && global.document.currentScript !== undefined) ? global.document.currentScript : null;
|
||||
const _scriptNode = (typeof document !== "undefined" && document.currentScript !== undefined) ? (document.currentScript as HTMLScriptElement) : null;
|
||||
|
||||
/**
|
||||
* Create a new web worker and returns a {@link libjass.webworker.WorkerChannel} to it.
|
||||
@@ -51,9 +51,9 @@ export function createWorker(scriptPath?: string): WorkerChannel {
|
||||
return new WorkerChannelImpl(new Worker(scriptPath));
|
||||
}
|
||||
|
||||
if (global.WorkerGlobalScope !== undefined && global instanceof global.WorkerGlobalScope) {
|
||||
// This is a web worker. Set up a channel to talk back to the main thread.
|
||||
declare const global: any;
|
||||
|
||||
/* tslint:disable-next-line:no-unused-expression */
|
||||
if (typeof WorkerGlobalScope !== "undefined" && global instanceof WorkerGlobalScope) {
|
||||
// This is a web worker. Set up a channel to talk back to the main thread.
|
||||
new WorkerChannelImpl(global);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
|
||||
import { Map } from "../utility/map";
|
||||
|
||||
import { WorkerCommandHandler } from "./channel";
|
||||
import { WorkerCommands } from "./commands";
|
||||
import { WorkerCommandHandler } from "./channel";
|
||||
|
||||
const workerCommands = new Map<WorkerCommands, WorkerCommandHandler>();
|
||||
|
||||
|
||||
Vendored
+37
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* libjass
|
||||
*
|
||||
* https://github.com/Arnavion/libjass
|
||||
*
|
||||
* Copyright 2013 Arnav Singh
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
interface WorkerGlobalScope {
|
||||
/**
|
||||
* @param {*} message
|
||||
*/
|
||||
postMessage(message: any): void;
|
||||
|
||||
/**
|
||||
* @param {string} type
|
||||
* @param {function(*)} listener
|
||||
* @param {boolean} useCapture
|
||||
*/
|
||||
addEventListener(type: string, listener: (message: any) => void, useCapture: boolean): void;
|
||||
}
|
||||
declare var WorkerGlobalScope: {
|
||||
prototype: WorkerGlobalScope;
|
||||
new (): WorkerGlobalScope;
|
||||
};
|
||||
Reference in New Issue
Block a user