diff --git a/.gitignore b/.gitignore index 36472a3b..035a7bb1 100644 --- a/.gitignore +++ b/.gitignore @@ -44,12 +44,7 @@ Thumbs.db *.suo *.sdf *.opensdf -externals/ build/ docs/html docs/latex -out/ -bin/ -ipch/ -resources/graphvis *.mo diff --git a/README.md b/README.md index a32acc61..a9badb06 100644 --- a/README.md +++ b/README.md @@ -40,40 +40,6 @@ BOSS requires the following libraries (version numbers used in latest developmen BOSS expects all libraries' folders to be present alongside the BOSS repository folder that contains this readme, or otherwise installed such that the compiler and linker used can find them without suppling additional paths. All paths below are relative to the folder(s) containing the libraries and BOSS. -BOSS can also make use of [GraphVis](http://www.graphviz.org/Download_windows.php) binaries. If provided, the following binaries should be placed into `resources/graphvis/` in the BOSS repository root: - -* cdt.dll -* cgraph.dll -* dot.exe -* freetype6.dll -* gvc.dll -* gvplugin_core.dll -* gvplugin_dot_layout.dll -* gvplugin_gd.dll -* gvplugin_pango.dll -* iconv.dll -* jpeg62.dll -* libcairo-2.dll -* libexpat.dll -* libfontconfig-1.dll -* libfreetype-6.dll -* libglib-2.0-0.dll -* libgmodule-2.0-0.dll -* libgobject-2.0-0.dll -* libgthread-2.0-0.dll -* libpango-1.0-0.dll -* libpangocairo-1.0-0.dll -* libpangoft2-1.0-0.dll -* libpangowin32-1.0-0.dll -* libpng12.dll -* libpng14-14.dll -* libxml2.dll -* ltdl.dll -* Pathplan.dll -* zlib1.dll - -Once the binaries have been placed there, run `dot.exe -c`. - Alphanum, Libespm and PugiXML do not require any additional setup. The rest of the libraries must be built separately. Instructions for building them and BOSS itself on Windows and Linux are given below. They assume that Visual C++ 2013 is being used on Windows, and mingw-w64 is being used on Linux, though they should be similar for other compilers. ### Windows diff --git a/docs/BOSS Readme.html b/docs/BOSS Readme.html index 5110d1a4..b58e0c80 100644 --- a/docs/BOSS Readme.html +++ b/docs/BOSS Readme.html @@ -162,9 +162,9 @@ Visual C++ Redistributable for Visual Studio 2013 (x86). BOSS can be install
Provided that masterlist updating is enabled and that an online masterlist URL is set, BOSS checks for updates to its masterlist and downloads any that are available. If there are any syntax errors in the latest masterlist (due to human error by its maintainers), the updater rolls back one version at a time until it finds a version that works. If any other errors are encountered, updating is cancelled. -
During the sorting process, BOSS extracts information from each of the plugins installed in the game's Data folder and combines this information with any relevant metadata provided by the masterlist and userlist. It then uses the combined data to build a graph (as in graph theory, not drawing) of all the interactions between all the installed plugins. A topological sort is then carried out on the graph to produce a list of plugins in their optimal load order, according to BOSS's criteria. If a cycle is detected (eg. A depends on B depends on A), then sorting is cancelled as it becomes impossible to generate a load order that satisfies all conditions. +
During the sorting process, BOSS extracts information from each of the plugins installed in the game's Data folder and combines this information with any relevant metadata provided by the masterlist and userlist. It then uses the combined data to build a directed graph of all the interactions between all the installed plugins. A topological sort is then carried out on the graph to produce a list of plugins in their optimal load order, according to BOSS's criteria. If a cycle is detected (eg. A depends on B depends on A), then sorting is cancelled as it becomes impossible to generate a load order that satisfies all conditions.
If successful, the calculated load order is then displayed in the dialog shown above, which allows the user to edit the load order before it is applied. Multiple plugins may be selected and moved at once. Plugins which are empty (ie. only contain a header record) are displayed in grey text, and plugins that are not empty and load BSAs are displayed in blue text. If OK
button is clicked, it is then applied, and any edits made are recorded in the userlist for re-application when BOSS next sorts the game's plugins. If the Cancel
button is clicked, then the load order and any edits made are discarded.
-
BOSS then generates a report and displays it either in a new window or in your default browser, according to the value of the relevant setting. Any errors encountered during the sorting process will be displayed in this report, including those due to graph cycles, missing dependencies or installed incompatible plugins. If it is enabled, an SVG image of the graph is generated for display in the report. See the next section for more information on the report. +
BOSS then generates a report and displays it either in a new window or in your default browser, according to the value of the relevant setting. Any errors encountered during the sorting process will be displayed in this report, including those due to graph cycles, missing dependencies or installed incompatible plugins. See the next section for more information on the report.
BOSS is able to sort plugins ghosted by Wrye *ash, and can extract Bash Tags and version numbers from plugin descriptions. Provided that they have the Filter Bash Tag present in their description, BOSS can recognise filter patches and so avoid displaying unnecessary error messages for any of their masters that may be missing.
While reading very large plugins, such as the game's main master file, BOSS may appear to stop responding: this is not an issue. The time it takes for BOSS to sort your load order depends primarily on the size of the masterlist being used, the total size of the files in your load order, and the number of plugins in your load order. The first run is likely to be longer than subsequent runs as BOSS needs to download the full masterlist, rather than just the changes made by updates. In testing, it was found that sorting ~90 plugins with a total size of ~350 MB and a 5 MB masterlist takes around 15 seconds, though performance will vary with computer hardware. @@ -181,7 +181,6 @@ Visual C++ Redistributable for Visual Studio 2013 (x86). BOSS can be install
Summarytab gives information on the versions of BOSS and the masterlist used, whether masterlist updating is enabled, and breaks down the numbers of each message type in the Summary and Details tabs. It also notifies you if there have been no changes in the
Detailstab since you last ran BOSS for the same game. Finally, the
Summarytab is also where any global messages supplied in the masterlist and any errors encountered during sorting are displayed.
Detailstab lists the plugins BOSS sorted in their new load order, along with any messages BOSS has provided for them. BOSS will also display the plugin's CRC value and extract its version if found in the plugin's description field. -
Graphtab displays a graph of all the interactions between the plugins in your load order. It's not very useful to the average user, but may contain information that would aid in debugging any issues encountered, and is also provided as an item of interest. Graph image generation typically takes a long time, so it is disabled by default.
In addition, there are a few filters that can be used to selectively hide items in the Details
tab. These filters are:
BOSS's sorting algorithm uses the contents of plugins to work out where they should load relative to one another. However, this is sometimes not enough for it to produce a correct load order. In such cases, additional metadata can be supplied so that the plugins get sorted correctly. This metadata is supplied to BOSS by two sources: one is the masterlist, which is maintained by the BOSS team, and the other is the userlist, which you can edit as you desire. -
The metadata editor allows you to manage the metadata stored in your userlist. When opened, it lists all the plugins you have installed, and any that are missing but have existing user-added metadata, in alphabetical order. Plugins that load BSAs are displayed in blue text. Clicking on a plugin then opens its metadata for editing, and displays any existing metadata in the fields to the right of the plugin list. These fields are explained in the table below. +
The metadata editor allows you to manage the metadata stored in your userlist. When opened, it lists all the plugins you have installed, and any that are missing but have existing user-added metadata, in alphabetical order. Plugins that load BSAs are displayed in blue text, and plugins with user-added metadata are displayed in bold text. Selecting a plugin then opens its metadata for editing, and displays any existing metadata in the fields to the right of the plugin list. Right-clicking a plugin displays a context menu containing a few commands. The editor fields and context menu commands are explained in the tables below.
The Add …
, Edit …
and Remove …
buttons are used to edit the contents of the list currently visible. The Edit …
and Remove …
buttons are greyed out if no row is selected or if the selected row is not user-added metadata, but comes from the masterlist or the plugin itself. Metadata that comes from the masterlist or the plugin itself cannot be edited or removed, only added to. This is to prevent users from accidently overriding important metadata.
-
The Copy Metadata As Text
copies the selected plugin's current metadata, as it appears in the userlist, to the clipboard. This makes it easier to share your metadata changes with the BOSS team, as they can then paste this text directly into the masterlist, and also avoids any typos being introduced. If posting the text in an online forum that supports BBCode (as most forums do), be sure to wrap it in [code] tags, eg. [code]copied text[/code], so that the spaces are not removed by the forum software.
The Save Changes
button will save any user-added metadata to your userlist, including any changes made, then exit the metadata editor. The Cancel
button will exit the editor without saving any changes.
| Context Menu Command | Description + |
|---|---|
| Copy Name | Copies the selected plugin's filename to the clipboard. + |
| Copy Metadata As Text | Copies the selected plugin's current metadata, as it appears in the userlist, to the clipboard. This makes it easier to share your metadata changes with the BOSS team, as they can then paste this text directly into the masterlist, and also avoids any typos being introduced. If posting the text in an online forum that supports BBCode (as most forums do), be sure to wrap it in [code] tags, eg. [code]copied text[/code], so that the spaces are not removed by the forum software.
+ |
| Remove All User-Added Metadata | This removes all saved user-added metadata from the selected plugin, and any unsaved data added to the plugin since the Metadata Editor window was opened. + |
@@ -261,7 +266,6 @@ Visual C++ Redistributable for Visual Studio 2013 (x86). BOSS can be install
%LOCALAPPDATA%\BOSS\BOSSDebugLog.txt.
The games list allows the customisation of which games BOSS offers support for, trivialising support for multiple copies of a game and Total Conversions. The games listed here will be displayed in the main window's Game
menu when BOSS is next run. The Add Game
, Edit Game
and Remove Game
buttons are used to edit the list. Each game has several columns, which are explained below.
| GitHub | Bethesda | Nexus | Oblivion | Skyrim | Fallout 3 | Fallout: New Vegas | ||
|---|---|---|---|---|---|---|---|---|
| Aellis-BOSS | Aellis | ✓ | ✓ | + | ||||
| egocarib | egocarib | - | ✓ | |||||
| Freso | ✓ | |||||||
| ineedbettername | - | ✓ | ||||||
| LotteryDiscountz | ✓ | |||||||
| niveuseverto | ✓ | |||||||
| noxwyll | iyumichan | ✓ | ✓ + | |||||
| PacificMorrowind | ✓ | ✓ | ||||||
| Sharlikran | ✓ | |||||||
| SilentSpike | SilentSpike69 | ✓ | ||||||
| TokcDK | Tokc.D.K. | ✓ | ✓ | - | ||||
| William Imm | ✓ | ✓ | + | |||||
| William-Imm | William Imm | WilliamImm | ✓ | ✓ | ||||
| WrinklyNinja | ✓ | ✓ | ||||||
The status of the following members is currently unknown: - -
| Member | Admin | Code | Contributes To Masterlist - | |||
|---|---|---|---|---|---|---|
| Oblivion | Skyrim | Fallout 3 | Fallout: New Vegas - | |||
| PacificMorrowind | ✓ | ✓ | ✓ | ✓ | - | |
| Random007 | ✓ | ✓ | ✓ | - | ||
| scrapperrm | ✓ | - | ||||
Members who have since left the project are credited below:
| Malonn | ✓ | |||||
| Peste | ✓ | |||||
| Psymon | ✓ | + | ||||
| Random007 | ✓ | ✓ | ✓ | |||
| Red Eye | ✓ | |||||
| RiddlingLynx | ✓ | + | ||||
| scrapperrm | ✓ | |||||
| Skyline | ✓ | |||||
| Space Oden69 | ✓ | |||||
| Televator | ✓ | @@ -520,7 +516,7 @@ There are three key pieces of information that are used to accurately describe a | ||||
| Masterlist structure & syntax | Uses a custom file format. | Uses YAML 1.2, with custom condition string syntax modelled after Python's condition expressions. | ||||
| Userlist structure & syntax | Uses a custom file format, different from the masterlist format. | Uses the same format and syntax as the masterlist. | ||||
| Morrowind support | Technically supports Morrowind, though its masterlist is near-empty. | Does not support Morrowind. - | ||||
| BOSS file locations | All BOSS's files are stored in the BOSS folder first installed. | BOSS stores any files it creates (reports, masterlists, userlists, settings, graphs) in the %LOCALAPPDATA%\BOSS folder.
+ | ||||
| BOSS file locations | All BOSS's files are stored in the BOSS folder first installed. | BOSS stores any files it creates (reports, masterlists, userlists, settings) in the %LOCALAPPDATA%\BOSS folder.
| ||||
| Game selection on first run. | BOSS asks the user to select a game from a list. | BOSS selects the first game detected. | ||||
| File CRC calculation | File CRC calculation is optional. | File CRC calculation is always-on, as it no longer presents any significant additional performance impact. | ||||
| BOSS Log / Report format | The BOSS Log can either be generated as plain text or as HTML. | The BOSS Report can only be generated as HTML.
diff --git a/docs/licenses/Licenses.txt b/docs/licenses/Licenses.txt
index a7beba85..85b03fde 100644
--- a/docs/licenses/Licenses.txt
+++ b/docs/licenses/Licenses.txt
@@ -9,15 +9,8 @@ BOSS uses a number of libraries, and their licenses are listed in this file.
* Libloadorder - GNU GPL v3; see "GNU GPL v3.txt" for the text.
* Polyfill.js - This code has been placed in the public domain.
* PugiXML - MIT License; see "MIT License (PugiXML).txt" for the text.
-* svgweb - Apache License v2.0; see "Apache License v2.0.txt" for the text.
* wxWidgets - wxWindows License; the text is not included as allowed by the license.
* yaml-cpp - MIT License; see "MIT License (yaml-cpp).txt" for the text.
* zlib - zlib license; the text is not included as allowed by the license.
-BOSS is also distributed with some binaries for the following programs:
-
-* GraphViz - Eclipse Public License v1.0; the text is not included as allowed by the license.
-
-Going by what the EPL FAQ page says, simply running the GraphVis binaries through system calls does not make BOSS a "derivative work", and so it is not bound by the EPL, and so it's OK for BOSS to use GraphVis even though the EPL and GPL are incompatible.
-
Source code for all libraries and binaries can be found on the websites linked to in the main BOSS readme.
diff --git a/resources/polyfill.js b/resources/polyfill.js
index 350699dd..32f66143 100644
--- a/resources/polyfill.js
+++ b/resources/polyfill.js
@@ -18,7 +18,7 @@
// since the constructor property is destroyed.
if (!Object.getPrototypeOf) {
Object.getPrototypeOf = function (o) {
- if (o !== Object(o)) { throw new TypeError("Object.getPrototypeOf called on non-object"); }
+ if (o !== Object(o)) { throw TypeError("Object.getPrototypeOf called on non-object"); }
return o.__proto__ || o.constructor.prototype || Object.prototype;
};
}
@@ -26,7 +26,7 @@ if (!Object.getPrototypeOf) {
// // ES5 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P )
// if (typeof Object.getOwnPropertyDescriptor !== "function") {
// Object.getOwnPropertyDescriptor = function (o, name) {
-// if (o !== Object(o)) { throw new TypeError(); }
+// if (o !== Object(o)) { throw TypeError(); }
// if (o.hasOwnProperty(name)) {
// return {
// value: o[name],
@@ -41,7 +41,7 @@ if (!Object.getPrototypeOf) {
// ES5 15.2.3.4 Object.getOwnPropertyNames ( O )
if (typeof Object.getOwnPropertyNames !== "function") {
Object.getOwnPropertyNames = function (o) {
- if (o !== Object(o)) { throw new TypeError("Object.getOwnPropertyNames called on non-object"); }
+ if (o !== Object(o)) { throw TypeError("Object.getOwnPropertyNames called on non-object"); }
var props = [], p;
for (p in o) {
if (Object.prototype.hasOwnProperty.call(o, p)) {
@@ -55,15 +55,14 @@ if (typeof Object.getOwnPropertyNames !== "function") {
// ES5 15.2.3.5 Object.create ( O [, Properties] )
if (typeof Object.create !== "function") {
Object.create = function (prototype, properties) {
- "use strict";
- if (typeof prototype !== "object") { throw new TypeError(); }
+ if (typeof prototype !== "object") { throw TypeError(); }
/** @constructor */
function Ctor() {}
Ctor.prototype = prototype;
var o = new Ctor();
if (prototype) { o.constructor = Ctor; }
- if (arguments.length > 1) {
- if (properties !== Object(properties)) { throw new TypeError(); }
+ if (properties !== undefined) {
+ if (properties !== Object(properties)) { throw TypeError(); }
Object.defineProperties(o, properties);
}
return o;
@@ -77,12 +76,10 @@ if (typeof Object.create !== "function") {
!(function () { try { Object.defineProperty({}, 'x', {}); return true; } catch (e) { return false; } } ())) {
var orig = Object.defineProperty;
Object.defineProperty = function (o, prop, desc) {
- "use strict";
-
// In IE8 try built-in implementation for defining properties on DOM prototypes.
if (orig) { try { return orig(o, prop, desc); } catch (e) {} }
- if (o !== Object(o)) { throw new TypeError("Object.defineProperty called on non-object"); }
+ if (o !== Object(o)) { throw TypeError("Object.defineProperty called on non-object"); }
if (Object.prototype.__defineGetter__ && ('get' in desc)) {
Object.prototype.__defineGetter__.call(o, prop, desc.get);
}
@@ -100,8 +97,7 @@ if (typeof Object.create !== "function") {
// ES 15.2.3.7 Object.defineProperties ( O, Properties )
if (typeof Object.defineProperties !== "function") {
Object.defineProperties = function (o, properties) {
- "use strict";
- if (o !== Object(o)) { throw new TypeError("Object.defineProperties called on non-object"); }
+ if (o !== Object(o)) { throw TypeError("Object.defineProperties called on non-object"); }
var name;
for (name in properties) {
if (Object.prototype.hasOwnProperty.call(properties, name)) {
@@ -117,7 +113,7 @@ if (typeof Object.defineProperties !== "function") {
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/keys
if (!Object.keys) {
Object.keys = function (o) {
- if (o !== Object(o)) { throw new TypeError('Object.keys called on non-object'); }
+ if (o !== Object(o)) { throw TypeError('Object.keys called on non-object'); }
var ret = [], p;
for (p in o) {
if (Object.prototype.hasOwnProperty.call(o, p)) {
@@ -140,7 +136,7 @@ if (!Object.keys) {
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind
if (!Function.prototype.bind) {
Function.prototype.bind = function (o) {
- if (typeof this !== 'function') { throw new TypeError("Bind must be called on a function"); }
+ if (typeof this !== 'function') { throw TypeError("Bind must be called on a function"); }
var slice = [].slice,
args = slice.call(arguments, 1),
self = this,
@@ -182,9 +178,7 @@ Array.isArray = Array.isArray || function (o) { return Boolean(o && Object.proto
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
if (!Array.prototype.indexOf) {
Array.prototype.indexOf = function (searchElement /*, fromIndex */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
@@ -217,9 +211,7 @@ if (!Array.prototype.indexOf) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
if (!Array.prototype.lastIndexOf) {
Array.prototype.lastIndexOf = function (searchElement /*, fromIndex*/) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
@@ -250,13 +242,11 @@ if (!Array.prototype.lastIndexOf) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
if (!Array.prototype.every) {
Array.prototype.every = function (fun /*, thisp */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
var thisp = arguments[1], i;
for (i = 0; i < len; i++) {
@@ -273,13 +263,11 @@ if (!Array.prototype.every) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
if (!Array.prototype.some) {
Array.prototype.some = function (fun /*, thisp */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
var thisp = arguments[1], i;
for (i = 0; i < len; i++) {
@@ -296,13 +284,11 @@ if (!Array.prototype.some) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/forEach
if (!Array.prototype.forEach) {
Array.prototype.forEach = function (fun /*, thisp */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
var thisp = arguments[1], i;
for (i = 0; i < len; i++) {
@@ -318,13 +304,11 @@ if (!Array.prototype.forEach) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Map
if (!Array.prototype.map) {
Array.prototype.map = function (fun /*, thisp */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
var res = []; res.length = len;
var thisp = arguments[1], i;
@@ -342,13 +326,11 @@ if (!Array.prototype.map) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Filter
if (!Array.prototype.filter) {
Array.prototype.filter = function (fun /*, thisp */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
var res = [];
var thisp = arguments[1], i;
@@ -370,16 +352,14 @@ if (!Array.prototype.filter) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/Reduce
if (!Array.prototype.reduce) {
Array.prototype.reduce = function (fun /*, initialValue */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof fun !== "function") { throw new TypeError(); }
+ if (typeof fun !== "function") { throw TypeError(); }
// no value to return if no initial value and an empty array
- if (len === 0 && arguments.length === 1) { throw new TypeError(); }
+ if (len === 0 && arguments.length === 1) { throw TypeError(); }
var k = 0;
var accumulator;
@@ -393,7 +373,7 @@ if (!Array.prototype.reduce) {
}
// if array contains no values, no initial value to return
- if (++k >= len) { throw new TypeError(); }
+ if (++k >= len) { throw TypeError(); }
}
while (true);
}
@@ -414,16 +394,14 @@ if (!Array.prototype.reduce) {
// From https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/ReduceRight
if (!Array.prototype.reduceRight) {
Array.prototype.reduceRight = function (callbackfn /*, initialValue */) {
- "use strict";
-
- if (this === void 0 || this === null) { throw new TypeError(); }
+ if (this === void 0 || this === null) { throw TypeError(); }
var t = Object(this);
var len = t.length >>> 0;
- if (typeof callbackfn !== "function") { throw new TypeError(); }
+ if (typeof callbackfn !== "function") { throw TypeError(); }
// no value to return if no initial value, empty array
- if (len === 0 && arguments.length === 1) { throw new TypeError(); }
+ if (len === 0 && arguments.length === 1) { throw TypeError(); }
var k = len - 1;
var accumulator;
@@ -437,7 +415,7 @@ if (!Array.prototype.reduceRight) {
}
// if array contains no values, no initial value to return
- if (--k < 0) { throw new TypeError(); }
+ if (--k < 0) { throw TypeError(); }
}
while (true);
}
@@ -510,54 +488,13 @@ if (!Date.prototype.toISOString) {
pad3(this.getUTCMilliseconds()) + 'Z';
};
}
-
-
-//----------------------------------------------------------------------
-//
-// Non-standard JavaScript (Mozilla) functions
-//
-//----------------------------------------------------------------------
-
-(function () {
- // JavaScript 1.8.1
- String.prototype.trimLeft = String.prototype.trimLeft || function () {
- return String(this).replace(/^\s+/, '');
- };
-
- // JavaScript 1.8.1
- String.prototype.trimRight = String.prototype.trimRight || function () {
- return String(this).replace(/\s+$/, '');
- };
-
- // JavaScript 1.?
- var ESCAPES = {
- //'\x00': '\\0', Special case in FF3.6, removed by FF10
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- };
- String.prototype.quote = String.prototype.quote || function() {
- return '"' + String(this).replace(/[\x00-\x1F"\\\x7F-\uFFFF]/g, function(c) {
- if (Object.prototype.hasOwnProperty.call(ESCAPES, c)) {
- return ESCAPES[c];
- } else if (c.charCodeAt(0) <= 0xFF) {
- return '\\x' + ('00' + c.charCodeAt(0).toString(16).toUpperCase()).slice(-2);
- } else {
- return '\\u' + ('0000' + c.charCodeAt(0).toString(16).toUpperCase()).slice(-4);
- }
- }) + '"';
- };
-}());
-
-
//----------------------------------------------------------------------
//
// Browser Polyfills
//
+// This assumes ES5 or ES3 + es5.js
+// (polyfill.js is es5.js + web.js for convenience)
+//
//----------------------------------------------------------------------
if ('window' in this && 'document' in this) {
@@ -581,7 +518,7 @@ if ('window' in this && 'document' in this) {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); } catch (e1) { }
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); } catch (e2) { }
try { return new ActiveXObject("Msxml2.XMLHTTP"); } catch (e3) { }
- throw new Error("This browser does not support XMLHttpRequest.");
+ throw Error("This browser does not support XMLHttpRequest.");
};
XMLHttpRequest.UNSENT = 0;
XMLHttpRequest.OPENED = 1;
@@ -589,6 +526,43 @@ if ('window' in this && 'document' in this) {
XMLHttpRequest.LOADING = 3;
XMLHttpRequest.DONE = 4;
+ //
+ // FormData (http://www.w3.org/TR/XMLHttpRequest2/#interface-formdata)
+ //
+ if (!('FormData' in window)) {
+ (function(global) {
+ function FormData(form) {
+ this._data = [];
+ if (!form) return;
+ for (var i = 0; i < form.elements.length; ++i)
+ this.append(form.elements[i].name, form.elements[i].value);
+ }
+
+ FormData.prototype.append = function(name, value /*, filename */) {
+ if ('Blob' in global && value instanceof global.Blob) throw TypeError("Blob not supported");
+ name = String(name);
+ this._data.push([name, value]);
+ };
+
+ FormData.prototype.toString = function() {
+ return this._data.map(function(pair) {
+ return encodeURIComponent(pair[0]) + '=' + encodeURIComponent(pair[1]);
+ }).join('&');
+ };
+
+ global.FormData = FormData;
+ var send = global.XMLHttpRequest.prototype.send;
+ global.XMLHttpRequest.prototype.send = function(body) {
+ if (body instanceof FormData) {
+ this.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
+ arguments[0] = body.toString();
+ }
+ return send.apply(this, arguments);
+ };
+ }(this));
+ }
+
+
//----------------------------------------------------------------------
//
// Performance
@@ -597,7 +571,7 @@ if ('window' in this && 'document' in this) {
// requestAnimationFrame
// http://www.w3.org/TR/animation-timing/
- (function() {
+ (function(global) {
var TARGET_FPS = 60,
requests = Object.create(null),
raf_handle = 1,
@@ -626,7 +600,7 @@ if ('window' in this && 'document' in this) {
requests[cb_handle] = {callback: callback, element: element};
if (timeout_handle === -1) {
- timeout_handle = window.setTimeout(onFrameTimer, 1000 / TARGET_FPS);
+ timeout_handle = global.setTimeout(onFrameTimer, 1000 / TARGET_FPS);
}
return cb_handle;
@@ -636,53 +610,53 @@ if ('window' in this && 'document' in this) {
delete requests[handle];
if (Object.keys(requests).length === 0) {
- window.clearTimeout(timeout_handle);
+ global.clearTimeout(timeout_handle);
timeout_handle = -1;
}
}
- window.requestAnimationFrame =
- window.requestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.oRequestAnimationFrame ||
- window.msRequestAnimationFrame ||
+ global.requestAnimationFrame =
+ global.requestAnimationFrame ||
+ global.webkitRequestAnimationFrame ||
+ global.mozRequestAnimationFrame ||
+ global.oRequestAnimationFrame ||
+ global.msRequestAnimationFrame ||
requestAnimationFrame;
// NOTE: Older versions of the spec called this "cancelRequestAnimationFrame"
- window.cancelAnimationFrame = window.cancelRequestAnimationFrame =
- window.cancelAnimationFrame || window.cancelRequestAnimationFrame ||
- window.webkitCancelAnimationFrame || window.webkitCancelRequestAnimationFrame ||
- window.mozCancelAnimationFrame || window.mozCancelRequestAnimationFrame ||
- window.oCancelAnimationFrame || window.oCancelRequestAnimationFrame ||
- window.msCancelAnimationFrame || window.msCancelRequestAnimationFrame ||
+ global.cancelAnimationFrame = global.cancelRequestAnimationFrame =
+ global.cancelAnimationFrame || global.cancelRequestAnimationFrame ||
+ global.webkitCancelAnimationFrame || global.webkitCancelRequestAnimationFrame ||
+ global.mozCancelAnimationFrame || global.mozCancelRequestAnimationFrame ||
+ global.oCancelAnimationFrame || global.oCancelRequestAnimationFrame ||
+ global.msCancelAnimationFrame || global.msCancelRequestAnimationFrame ||
cancelAnimationFrame;
- }());
+ }(this));
// setImmediate
// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/setImmediate/Overview.html
- (function () {
- function setImmediate(callback, args) {
- var params = [].slice.call(arguments, 1), i;
- return window.setTimeout(function() {
+ (function (global) {
+ function setImmediate(callback/*, args*/) {
+ var params = [].slice.call(arguments, 1);
+ return global.setTimeout(function() {
callback.apply(null, params);
}, 0);
}
function clearImmediate(handle) {
- window.clearTimeout(handle);
+ global.clearTimeout(handle);
}
- window.setImmediate =
- window.setImmediate ||
- window.msSetImmediate ||
+ global.setImmediate =
+ global.setImmediate ||
+ global.msSetImmediate ||
setImmediate;
- window.clearImmediate =
- window.clearImmediate ||
- window.msClearImmediate ||
+ global.clearImmediate =
+ global.clearImmediate ||
+ global.msClearImmediate ||
clearImmediate;
- } ());
+ }(this));
//----------------------------------------------------------------------
//
@@ -728,10 +702,18 @@ if ('window' in this && 'document' in this) {
};
}
+ // Fix for IE8-'s Element.getBoundingClientRect()
+ if ('TextRectangle' in this && !('width' in TextRectangle.prototype)) {
+ Object.defineProperties(TextRectangle.prototype, {
+ 'width': { get: function() { return this.right - this.left; } },
+ 'height': { get: function() { return this.bottom - this.top; } }
+ });
+ }
+
//
// DOM Enumerations (http://www.w3.org/TR/DOM-Level-2-Core/)
//
- window.Node = window.Node || function Node() { throw new TypeError("Illegal constructor"); };
+ window.Node = window.Node || function Node() { throw TypeError("Illegal constructor"); };
Node.ELEMENT_NODE = 1;
Node.ATTRIBUTE_NODE = 2;
Node.TEXT_NODE = 3;
@@ -745,7 +727,7 @@ if ('window' in this && 'document' in this) {
Node.DOCUMENT_FRAGMENT_NODE = 11;
Node.NOTATION_NODE = 12;
- window.DOMException = window.DOMException || function DOMException() { throw new TypeError("Illegal constructor"); };
+ window.DOMException = window.DOMException || function DOMException() { throw TypeError("Illegal constructor"); };
DOMException.INDEX_SIZE_ERR = 1;
DOMException.DOMSTRING_SIZE_ERR = 2;
DOMException.HIERARCHY_REQUEST_ERR = 3;
@@ -777,108 +759,96 @@ if ('window' in this && 'document' in this) {
Event.AT_TARGET = 2;
Event.BUBBLING_PHASE = 3;
- Object.defineProperty(Event.prototype, 'CAPTURING_PHASE', { get: function() { return 1; } });
- Object.defineProperty(Event.prototype, 'AT_TARGET', { get: function() { return 2; } });
- Object.defineProperty(Event.prototype, 'BUBBLING_HASE', { get: function() { return 3; } });
-
- Object.defineProperty(Event.prototype, 'target', {
- get: function() {
- return this.srcElement;
- }
+ Object.defineProperties(Event.prototype, {
+ CAPTURING_PHASE: { get: function() { return 1; } },
+ AT_TARGET: { get: function() { return 2; } },
+ BUBBLING_HASE: { get: function() { return 3; } },
+ target: {
+ get: function() {
+ return this.srcElement;
+ }},
+ currentTarget: {
+ get: function() {
+ return this._currentTarget;
+ }},
+ eventPhase: {
+ get: function() {
+ return (this.srcElement === this.currentTarget) ? Event.AT_TARGET : Event.BUBBLING_PHASE;
+ }},
+ bubbles: {
+ get: function() {
+ switch (this.type) {
+ // Mouse
+ case 'click':
+ case 'dblclick':
+ case 'mousedown':
+ case 'mouseup':
+ case 'mouseover':
+ case 'mousemove':
+ case 'mouseout':
+ case 'mousewheel':
+ // Keyboard
+ case 'keydown':
+ case 'keypress':
+ case 'keyup':
+ // Frame/Object
+ case 'resize':
+ case 'scroll':
+ // Form
+ case 'select':
+ case 'change':
+ case 'submit':
+ case 'reset':
+ return true;
+ }
+ return false;
+ }},
+ cancelable: {
+ get: function() {
+ switch (this.type) {
+ // Mouse
+ case 'click':
+ case 'dblclick':
+ case 'mousedown':
+ case 'mouseup':
+ case 'mouseover':
+ case 'mouseout':
+ case 'mousewheel':
+ // Keyboard
+ case 'keydown':
+ case 'keypress':
+ case 'keyup':
+ // Form
+ case 'submit':
+ return true;
+ }
+ return false;
+ }},
+ timeStamp: {
+ get: function() {
+ return this._timeStamp;
+ }},
+ stopPropagation: {
+ value: function() {
+ this.cancelBubble = true;
+ }},
+ preventDefault: {
+ value: function() {
+ this.returnValue = false;
+ }},
+ defaultPrevented: {
+ get: function() {
+ return this.returnValue === false;
+ }}
});
- Object.defineProperty(Event.prototype, 'currentTarget', {
- get: function() {
- return this._currentTarget;
- }
- });
-
- Object.defineProperty(Event.prototype, 'eventPhase', {
- get: function() {
- return (this.srcElement === this.currentTarget) ? Event.AT_TARGET : Event.BUBBLING_PHASE;
- }
- });
-
- Object.defineProperty(Event.prototype, 'bubbles', {
- get: function() {
- switch (this.type) {
- // Mouse
- case 'click':
- case 'dblclick':
- case 'mousedown':
- case 'mouseup':
- case 'mouseover':
- case 'mousemove':
- case 'mouseout':
- case 'mousewheel':
- // Keyboard
- case 'keydown':
- case 'keypress':
- case 'keyup':
- // Frame/Object
- case 'resize':
- case 'scroll':
- // Form
- case 'select':
- case 'change':
- case 'submit':
- case 'reset':
- return true;
- }
- return false;
- }
- });
-
- Object.defineProperty(Event.prototype, 'cancelable', {
- get: function() {
- switch (this.type) {
- // Mouse
- case 'click':
- case 'dblclick':
- case 'mousedown':
- case 'mouseup':
- case 'mouseover':
- case 'mouseout':
- case 'mousewheel':
- // Keyboard
- case 'keydown':
- case 'keypress':
- case 'keyup':
- // Form
- case 'submit':
- return true;
- }
- return false;
- }
- });
-
- Object.defineProperty(Event.prototype, 'timeStamp', {
- get: function() {
- return this._timeStamp;
- }
- });
-
- Event.prototype.stopPropagation = function() {
- this.cancelBubble = true;
- };
-
- Event.prototype.preventDefault = function() {
- this.returnValue = false;
- };
-
- Object.defineProperty(Event.prototype, 'defaultPrevented', {
- get: function() {
- return this.returnValue === false;
- }
- });
-
-
// interface EventTarget
function addEventListener(type, listener, useCapture) {
+ if (type === 'DOMContentLoaded') type = 'load';
var target = this;
var f = function(e) {
- e._timeStamp = Number(new Date);
+ e._timeStamp = Date.now();
e._currentTarget = target;
listener.call(this, e);
e._currentTarget = null;
@@ -888,6 +858,7 @@ if ('window' in this && 'document' in this) {
}
function removeEventListener(type, listener, useCapture) {
+ if (type === 'DOMContentLoaded') type = 'load';
var f = this['_' + type + listener];
if (f) {
this.detachEvent('on' + type, f);
@@ -895,9 +866,10 @@ if ('window' in this && 'document' in this) {
}
}
- var p1 = Window.prototype, p2 = HTMLDocument.prototype, p3 = Element.prototype;
- p1.addEventListener = p2.addEventListener = p3.addEventListener = addEventListener;
- p1.removeEventListener = p2.removeEventListener = p3.removeEventListener = removeEventListener;
+ [Window, HTMLDocument, Element].forEach(function(o) {
+ o.prototype.addEventListener = addEventListener;
+ o.prototype.removeEventListener = removeEventListener;
+ });
}());
@@ -916,7 +888,7 @@ if ('window' in this && 'document' in this) {
e.preventDefault = function () { e.returnValue = false; };
e.stopPropagation = function () { e.cancelBubble = true; };
e.target = e.srcElement;
- e.timeStamp = Number(new Date);
+ e.timeStamp = Date.now();
obj["e" + type + fn].call(this, e);
};
obj.attachEvent("on" + type, obj[type + fn]);
@@ -976,8 +948,8 @@ if ('window' in this && 'document' in this) {
contains: {
value: function (token) {
token = String(token);
- if (token.length === 0) { throw new SyntaxError(); }
- if (/\s/.test(token)) { throw new Error("InvalidCharacterError"); }
+ if (token.length === 0) { throw SyntaxError(); }
+ if (/\s/.test(token)) { throw Error("InvalidCharacterError"); }
var tokens = split(o[p]);
return tokens.indexOf(token) !== -1;
@@ -985,13 +957,13 @@ if ('window' in this && 'document' in this) {
},
add: {
- value: function (tokens___) {
- tokens = Array.prototype.slice.call(arguments).map(String);
+ value: function (/*tokens...*/) {
+ var tokens = Array.prototype.slice.call(arguments).map(String);
if (tokens.some(function(token) { return token.length === 0; })) {
- throw new SyntaxError();
+ throw SyntaxError();
}
- if (tokens.some(function(token) { return /\s/.test(token); })) {
- throw new Error("InvalidCharacterError");
+ if (tokens.some(function(token) { return (/\s/).test(token); })) {
+ throw Error("InvalidCharacterError");
}
try {
@@ -1001,7 +973,7 @@ if ('window' in this && 'document' in this) {
if (tokens.length === 0) {
return;
}
- if (underlying_string.length !== 0 && !/\s$/.test(underlying_string)) {
+ if (underlying_string.length !== 0 && !(/\s$/).test(underlying_string)) {
underlying_string += ' ';
}
underlying_string += tokens.join(' ');
@@ -1014,13 +986,13 @@ if ('window' in this && 'document' in this) {
},
remove: {
- value: function (tokens___) {
- tokens = Array.prototype.slice.call(arguments).map(String);
+ value: function (/*tokens...*/) {
+ var tokens = Array.prototype.slice.call(arguments).map(String);
if (tokens.some(function(token) { return token.length === 0; })) {
- throw new SyntaxError();
+ throw SyntaxError();
}
- if (tokens.some(function(token) { return /\s/.test(token); })) {
- throw new Error("InvalidCharacterError");
+ if (tokens.some(function(token) { return (/\s/).test(token); })) {
+ throw Error("InvalidCharacterError");
}
try {
@@ -1040,8 +1012,8 @@ if ('window' in this && 'document' in this) {
value: function (token, force) {
try {
token = String(token);
- if (token.length === 0) { throw new SyntaxError(); }
- if (/\s/.test(token)) { throw new Error("InvalidCharacterError"); }
+ if (token.length === 0) { throw SyntaxError(); }
+ if (/\s/.test(token)) { throw Error("InvalidCharacterError"); }
var tokens = split(o[p]),
index = tokens.indexOf(token);
@@ -1114,6 +1086,7 @@ if ('window' in this && 'document' in this) {
var attr = this.attributes[i];
if (attr.specified && attr.name.substring(0, 5) === 'data-') {
(function(element, name) {
+ result[name] = element.getAttribute('data-' + name); // Read-only, for IE8-
Object.defineProperty(result, name, {
get: function() {
return element.getAttribute('data-' + name);
@@ -1124,7 +1097,7 @@ if ('window' in this && 'document' in this) {
}(this, attr.name.substring(5)));
}
}
- return result;
+ return result;
}});
}
}
@@ -1142,8 +1115,8 @@ if ('window' in this && 'document' in this) {
input = input.replace(/\s/g, '');
if ((input.length % 4) === 0) { input = input.replace(/=+$/, ''); }
- if ((input.length % 4) === 1) { throw new Error("InvalidCharacterError"); }
- if (/[^+/0-9A-Za-z]/.test(input)) { throw new Error("InvalidCharacterError"); }
+ if ((input.length % 4) === 1) { throw Error("InvalidCharacterError"); }
+ if (/[^+/0-9A-Za-z]/.test(input)) { throw Error("InvalidCharacterError"); }
while (position < input.length) {
n = B64_ALPHABET.indexOf(input.charAt(position));
@@ -1179,7 +1152,7 @@ if ('window' in this && 'document' in this) {
o1, o2, o3,
e1, e2, e3, e4;
- if (/[^\x00-\xFF]/.test(input)) { throw new Error("InvalidCharacterError"); }
+ if (/[^\x00-\xFF]/.test(input)) { throw Error("InvalidCharacterError"); }
while (position < input.length) {
o1 = input.charCodeAt(position++);
@@ -1207,4 +1180,46 @@ if ('window' in this && 'document' in this) {
return out.join('');
};
-} (this));
+}(this));
+
+
+//----------------------------------------------------------------------
+//
+// Non-standard JavaScript (Mozilla) functions
+//
+//----------------------------------------------------------------------
+
+(function () {
+ // JavaScript 1.8.1
+ String.prototype.trimLeft = String.prototype.trimLeft || function () {
+ return String(this).replace(/^\s+/, '');
+ };
+
+ // JavaScript 1.8.1
+ String.prototype.trimRight = String.prototype.trimRight || function () {
+ return String(this).replace(/\s+$/, '');
+ };
+
+ // JavaScript 1.?
+ var ESCAPES = {
+ //'\x00': '\\0', Special case in FF3.6, removed by FF10
+ '\b': '\\b',
+ '\t': '\\t',
+ '\n': '\\n',
+ '\f': '\\f',
+ '\r': '\\r',
+ '"' : '\\"',
+ '\\': '\\\\'
+ };
+ String.prototype.quote = String.prototype.quote || function() {
+ return '"' + String(this).replace(/[\x00-\x1F"\\\x7F-\uFFFF]/g, function(c) {
+ if (Object.prototype.hasOwnProperty.call(ESCAPES, c)) {
+ return ESCAPES[c];
+ } else if (c.charCodeAt(0) <= 0xFF) {
+ return '\\x' + ('00' + c.charCodeAt(0).toString(16).toUpperCase()).slice(-2);
+ } else {
+ return '\\u' + ('0000' + c.charCodeAt(0).toString(16).toUpperCase()).slice(-4);
+ }
+ }) + '"';
+ };
+}());
diff --git a/resources/style.css b/resources/style.css
index 4b93c90a..fbec65ba 100644
--- a/resources/style.css
+++ b/resources/style.css
@@ -53,6 +53,7 @@ noscript div {
.button[id] {
position:absolute;
right:0;
+ top:0;
}
#main {
position:absolute;
diff --git a/resources/svgweb/svg.htc b/resources/svgweb/svg.htc
deleted file mode 100644
index de76ff8f..00000000
--- a/resources/svgweb/svg.htc
+++ /dev/null
@@ -1 +0,0 @@
- |