Skip to content

Commit

Permalink
RELEASE: v2.36.0
Browse files Browse the repository at this point in the history
## Changelog:

* Fixed an issue with the `selected` keyword in the `<<cycle>>` and `<<listbox>>` macros' `<<option>>` tags.
* Fixed instances where using the `[img[]]` markup as an argument to macros would drop the `link-image` class.
* Fixed `Config.history.maxStates` to disallow unlimited states (value: `0`).
* Added the `init` special tag that, similar to `StoryInit`, allows pre-story-start initialization tasks.  Intended for add-on/library use.
* Added a `data-init-passage` content attribute to `StoryInterface` that allows content to be updated only once at initialization.
* Added the `State.metadata.entries()` and `State.metadata.keys()` static methods.
* Added a `once` keyword to the `<<cycle>>` macro that ends the cycle upon reaching the final option.
* Added the `<Array>.countWith()` method.
* Added the `Save` Events API.
* Added support for template literals within TwineScript.
* Added various accessibility improvements.
* Updated the `<<done>>` macro to better serve when used to wait for DOM updates.
* `<<widget>>` macro updates:
	* Added a `container` keyword that allows non-void/container widgets and an associated `_contents` special variable.
	* Added a new special arguments variable, `_args`, and deprecated the old variable, `$args`.
* Updated the default value of `Config.history.maxStates` from `100` to `40`.
* Updated passage objects to maintain the order of passage tags as specified in the data chunk.
* Deprecated the `Config.saves.onLoad` and `Config.saves.onSave` settings in favor of the `Save` Events API.
* Updated bundled library: `jQuery` to v3.6.0.
* Updates to locale files:
	* Updated the localization template.  Translators are asked to updated the locale files as necessary.
	* Added `nl.js` – Dutch.
* Various documentation updates.
* Various internal improvements.
* Build system updates.
  • Loading branch information
tmedwards authored Dec 21, 2021
2 parents dab0534 + aa8f36b commit bac3c41
Show file tree
Hide file tree
Showing 61 changed files with 8,720 additions and 5,662 deletions.
154 changes: 30 additions & 124 deletions build.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
#!/usr/bin/env node
/***********************************************************************************************************************
build.js (v1.4.18, 2020-11-08)
build.js (v1.6.0, 2021-12-19)
A Node.js-hosted build script for SugarCube.
Copyright © 2013–2020 Thomas Michael Edwards <[email protected]>. All rights reserved.
Copyright © 2013–2021 Thomas Michael Edwards <[email protected]>. All rights reserved.
Use of this source code is governed by a BSD 2-clause "Simplified" License, which may be found in the LICENSE file.
***********************************************************************************************************************/
/* eslint-env node, es6 */
/* eslint-disable strict */
'use strict';

/*******************************************************************************
Expand Down Expand Up @@ -142,11 +141,18 @@ const CONFIG = {
the replacement strings (e.g. '$&' within the application source).
*/

const _fs = require('fs');
const {
log,
die,
fileExists,
makePath,
copyFile,
readFileContents,
writeFileContents,
concatFiles
} = require('./scripts/build-utils');
const _path = require('path');

const _indent = ' -> ';
const _opt = require('node-getopt').create([
const _opt = require('node-getopt').create([
['b', 'build=VERSION', 'Build only for Twine major version: 1 or 2; default: build for all.'],
['d', 'debug', 'Keep debugging code; gated by DEBUG symbol.'],
['u', 'unminified', 'Suppress minification stages.'],
Expand Down Expand Up @@ -186,7 +192,7 @@ if (_opt.options.build) {
console.log('Starting builds...');

// Create the build ID file, if nonexistent.
if (!_fs.existsSync('.build')) {
if (!fileExists('.build')) {
writeFileContents('.build', '0');
}

Expand All @@ -203,7 +209,7 @@ if (_opt.options.build) {
patch : semver.patch(version),
prerelease : prerelease && prerelease.length > 0 ? prerelease.join('.') : null,
build : Number(readFileContents('.build')) + 1,
date : (new Date()).toISOString(),
date : new Date().toISOString(),

toString() {
const prerelease = this.prerelease ? `-${this.prerelease}` : '';
Expand Down Expand Up @@ -277,93 +283,6 @@ console.log('\nBuilds complete! (check the "build" directory)');
/*******************************************************************************
Utility Functions
*******************************************************************************/
function log(message, indent) {
console.log('%s%s', indent ? indent : _indent, message);
}

// function warn(message) {
// console.warn('%swarning: %s', _indent, message);
// }

function die(message, error) {
if (error) {
console.error('error: %s\n[@: %d/%d] Trace:\n', message, error.line, error.col, error.stack);
}
else {
console.error('error: %s', message);
}

process.exit(1);
}

function makePath(pathname) {
const pathBits = _path.normalize(pathname).split(_path.sep);

for (let i = 0; i < pathBits.length; ++i) {
const dirPath = i === 0 ? pathBits[i] : pathBits.slice(0, i + 1).join(_path.sep);

if (!_fs.existsSync(dirPath)) {
_fs.mkdirSync(dirPath);
}
}
}

function copyFile(srcFilename, destFilename) {
const srcPath = _path.normalize(srcFilename);
const destPath = _path.normalize(destFilename);
let buf;

try {
buf = _fs.readFileSync(srcPath);
}
catch (ex) {
die(`cannot open file "${srcPath}" for reading (reason: ${ex.message})`);
}

try {
_fs.writeFileSync(destPath, buf);
}
catch (ex) {
die(`cannot open file "${destPath}" for writing (reason: ${ex.message})`);
}

return true;
}

function readFileContents(filename) {
const filepath = _path.normalize(filename);

try {
// the replace() is necessary because Node.js only offers binary mode file
// access, regardless of platform, so we convert DOS-style line terminators
// to UNIX-style, just in case someone adds/edits a file and gets DOS-style
// line termination all over it
return _fs.readFileSync(filepath, { encoding : 'utf8' }).replace(/\r\n/g, '\n');
}
catch (ex) {
die(`cannot open file "${filepath}" for reading (reason: ${ex.message})`);
}
}

function writeFileContents(filename, data) {
const filepath = _path.normalize(filename);

try {
_fs.writeFileSync(filepath, data, { encoding : 'utf8' });
}
catch (ex) {
die(`cannot open file "${filepath}" for writing (reason: ${ex.message})`);
}
}

function concatFiles(filenames, callback) {
const output = filenames.map(filename => {
const contents = readFileContents(filename);
return typeof callback === 'function' ? callback(contents, filename) : contents;
});
return output.join('\n');
}

function assembleLibraries(filenames) {
log('assembling libraries...');

Expand Down Expand Up @@ -397,37 +316,24 @@ function compileJavaScript(filenameObj, options) {
].join(';\n') + ';\n' + jsSource;
}

try {
const uglifyjs = require('uglify-js');
const uglified = uglifyjs.minify(jsSource, {
fromString : true,
compress : {
global_defs : {
TWINE1 : !!options.twine1,
DEBUG : _opt.options.debug || false
},
screw_ie8 : true
},
mangle : {
screw_ie8 : true
const uglifyjs = require('uglify-js');
const minified = uglifyjs.minify(jsSource, {
compress : {
global_defs : {
TWINE1 : !!options.twine1,
DEBUG : _opt.options.debug || false
},
output : {
screw_ie8 : true
}
});
return uglified.code;
}
catch (ex) {
let mesg = 'uglification error';

if (ex.line > 0) {
const begin = ex.line > 4 ? ex.line - 4 : 0;
const end = ex.line + 3 < jsSource.length ? ex.line + 3 : jsSource.length;
mesg += ':\n >> ' + jsSource.split(/\n/).slice(begin, end).join('\n >> ');
}
keep_infinity : true
},
mangle : false
});

die(mesg, ex);
if (minified.error) {
const { message, line, col, pos } = minified.error;
die(`JavaScript minification error: ${message}\n[@: ${line}/${col}/${pos}]`);
}

return minified.code;
/* eslint-enable camelcase, prefer-template */
}

Expand Down
2 changes: 1 addition & 1 deletion dist/format.js

Large diffs are not rendered by default.

146 changes: 49 additions & 97 deletions docs/api/api-config.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,25 +75,27 @@ Config.history.controls = false;

<!-- *********************************************************************** -->

### `Config.history.maxStates`*integer* (default: `100`) {#config-api-property-history-maxstates}
### `Config.history.maxStates`*integer* (default: `40`) {#config-api-property-history-maxstates}

Sets the maximum number of states (moments) to which the history is allowed to grow. Should the history exceed the limit, states will be dropped from the past (oldest first). A setting of `0` means that there is no limit to how large the history may grow, though doing so is not recommended.
Sets the maximum number of states (moments) to which the history is allowed to grow. Should the history exceed the limit, states will be dropped from the past (oldest first).

<p role="note" class="tip"><b>Tip:</b>
For game-oriented projects, as opposed to more story-oriented interactive fiction, a setting of <code>1</code> is <strong><em>strongly recommended</em></strong>.
</p>

#### History:

* `v2.0.0`: Introduced.
* `v2.36.0`: Reduced the default to `40`.

#### Examples:

```
// No history limit (you should never do this!)
Config.history.maxStates = 0;
// Limit the history to a single state
// Limit the history to a single state (recommended for games)
Config.history.maxStates = 1;
// Limit the history to 150 states
Config.history.maxStates = 150;
// Limit the history to 80 states
Config.history.maxStates = 80;
```


Expand Down Expand Up @@ -426,9 +428,16 @@ Config.saves.autoload = function () {

<!-- *********************************************************************** -->

### `Config.saves.autosave`*boolean* | *string array* | *function* (default: *none*) {#config-api-property-saves-autosave}
### `Config.saves.autosave`*boolean* | *Array&lt;string&gt;* | *function* (default: *none*) {#config-api-property-saves-autosave}

Determines whether the autosave is created/updated when passages are displayed.

Valid values are:

Determines whether the autosave is created/updated when passages are displayed. Valid values are boolean `true`, which causes the autosave to be updated with every passage, an array of strings, which causes the autosave to be updated for each passage with at least one matching tag, or a function, which causes the autosave to be updated for each passage where its return value is truthy.
* Boolean `true`, which causes the autosave to be updated with every passage.
* Boolean `false`, which causes the autosave to never update automatically—i.e., you must do it manually via the <a href="#save-api-method-autosave-save"><code>Save.autosave.save()</code> static method</a>.
* An array of strings, which causes the autosave to be updated for each passage with at least one matching tag.
* A function, which causes the autosave to be updated for each passage where its return value is truthy.

<p role="note" class="warning"><b>Warning:</b>
When setting the value to boolean <code>true</code>, you will likely also need to use the <a href="#config-api-property-saves-isallowed"><code>Config.saves.isAllowed</code> property</a> to disallow saving on the start passage. Or, if you use the start passage as real part of your story and allow the player to reenter it, rather than just as the initial landing/cover page, then you may wish to only disallow saving on the start passage the very first time it's displayed—i.e., at story startup.
Expand All @@ -445,6 +454,9 @@ When setting the value to boolean <code>true</code>, you will likely also need t
// Autosaves every passage
Config.saves.autosave = true;
// Allows manual autosaving
Config.saves.autosave = false;
// Autosaves on passages tagged with any of "bookmark" or "autosave"
Config.saves.autosave = ["bookmark", "autosave"];
Expand Down Expand Up @@ -490,93 +502,6 @@ Config.saves.isAllowed = function () {

<!-- *********************************************************************** -->

### `Config.saves.onLoad`*function* (default: *none*) {#config-api-property-saves-onload}

Performs any required pre-processing before the save data is loaded—e.g., upgrading out-of-date save data. The callback is passed one parameter, the save object to be processed. If it encounters an unrecoverable problem during its processing, it may throw an exception containing an error message; the message will be displayed to the player and loading of the save will be terminated.

#### History:

* `v2.0.0`: Introduced.

#### Callback parameters:

* **`save`:** (*object*) The save object to be pre-processed.

#### Save object:

<p role="note"><b>Note:</b>
See the <a href="#save-api-save-objects">save objects</a> section of the <a href="#save-api">Save API</a> for information on the format of a save.
</p>

#### Examples:

```
Config.saves.onLoad = function (save) {
/* code to pre-process the save object */
};
```

<!-- *********************************************************************** -->

### `Config.saves.onSave`*function* (default: *none*) {#config-api-property-saves-onsave}

Performs any required post-processing before the save data is saved. The callback is passed two parameters, the save object to be processed and save operation details object.

#### History:

* `v2.0.0`: Introduced.
* `v2.33.0`: Added save operation details object parameter to the callback function.

#### Callback parameters:

* **`save`:** (*object*) The save object to be post-processed.
* **`details`:** (*object*) The save operation details object.

#### Save object:

<p role="note"><b>Note:</b>
See the <a href="#save-api-save-objects">save objects</a> section of the <a href="#save-api">Save API</a> for information on the format of a save.
</p>

#### Save operation details object:

A save operation details object will have the following properties:

* **`type`:** (*string*) A string representing how the save operation came about—i.e., what caused it. Possible values are: `'autosave'`, `'disk'`, `'serialize'`, `'slot'`.

#### Examples:

##### Using only the save object parameter

```
Config.saves.onSave = function (save) {
/* code to post-process the save object */
};
```

##### Using both the save object and operation details parameters

```
Config.saves.onSave = function (save, details) {
switch (details.type) {
case 'autosave':
/* code to post-process the save object from autosaves */
break;
case 'disk':
/* code to post-process the save object from disk saves */
break;
case 'serialize':
/* code to post-process the save object from serialize saves */
break;
default: /* slot */
/* code to post-process the save object from slot saves */
break;
}
};
```

<!-- *********************************************************************** -->

### `Config.saves.slots` *integer* (default: `8`) {#config-api-property-saves-slots}

Sets the maximum number of available save slots.
Expand Down Expand Up @@ -636,6 +561,33 @@ Config.saves.version = 3;
Config.saves.version = "v3";
```

<!-- *********************************************************************** -->

### <span class="deprecated">`Config.saves.onLoad`*function* (default: *none*)</span> {#config-api-property-saves-onload}

<p role="note" class="warning"><b>Deprecated:</b>
This setting has been deprecated and should no longer be used. See the <a href="#save-api-method-onload-add"><code>Save.onLoad.add()</code></a> method for its replacement.
</p>

#### History:

* `v2.0.0`: Introduced.
* `v2.36.0`: Deprecated in favor of the [`Save` Events API](#save-api-events).

<!-- *********************************************************************** -->

### <span class="deprecated">`Config.saves.onSave`*function* (default: *none*)</span> {#config-api-property-saves-onsave}

<p role="note" class="warning"><b>Deprecated:</b>
This setting has been deprecated and should no longer be used. See the <a href="#save-api-method-onsave-add"><code>Save.onSave.add()</code></a> method for its replacement.
</p>

#### History:

* `v2.0.0`: Introduced.
* `v2.33.0`: Added save operation details object parameter to the callback function.
* `v2.36.0`: Deprecated in favor of the [`Save` Events API](#save-api-events).


<!-- ***************************************************************************
UI
Expand Down
Loading

0 comments on commit bac3c41

Please sign in to comment.