Commit 1957ba6b authored by Leon Arnott's avatar Leon Arnott
Browse files

Improved the performance of Debug Mode's panels when updating individual entries.

Also:
 * Fixed a bug where the variable source rows revealed by the (source:) button would abruptly close whenever another entry in one of the panels was updated.
 * The 'Errors' tab now changes colour when the first error has occurred in the story.
parent d7d12e011b8b
......@@ -16,6 +16,7 @@ Documentation is at http://twine2.neocities.org/. See below for compilation inst
* Fixed a bug where a Javascript error would be produced when 0 was used in a substring or subarray data name, such as `$a's (range:0,2)`. Now, a proper error message will be given.
* Fixed a long-standing bug where a string containing \ followed by a newline would result in the newline transforming into the letter "n".
* Debug Mode: fixed a bug where values in the Variables pane would sometimes be truncated incorrectly, causing partial HTML entities like "&am…" to appear.
* Debug Mode: fixed a bug where the variable source rows revealed by the `(source:)` button would abruptly close whenever another entry in one of the panels was updated.
#### Alterations
......@@ -25,6 +26,8 @@ Documentation is at http://twine2.neocities.org/. See below for compilation inst
* `(mock-visits:)` effects are now saved using `(save-game:)` in Debug Mode.
* Added `newline` as an alias for the `linebreak` datatype. (Some parts of the documentation previously erroneously used the former instead of the latter.)
* Editor: disabled the "overwrite" input mode that was toggled by pressing Insert, because I've decided it's too confusing and easy to activate accidentally.
* Improved the performance of Debug Mode's panels when updating individual entries.
* Debug Mode: The 'Errors' tab now changes colour when the first error has occurred in the story.
### 3.2.2 changes (May 12, 2021):
......
......@@ -181,7 +181,7 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
let localTempVariables = new Set();
const Variables = Panel.create({
className: "variables", tabName: "Variable",
rowAdd({name, dataset, path, value, tempScope, type}) {
rowWrite({name, dataset, path, value, tempScope, type}, row) {
/*
The debug name used defers to the TwineScript_DebugName if it exists,
and falls back to the objectName if not. Note that the TwineScript_DebugName can contain HTML structures
......@@ -218,6 +218,24 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
Source code for objects can be viewed with a folddown button.
*/
const folddown = typeof value === "object" || tooLong;
/*
Freshen up the passed-in row if given.
*/
if (row) {
row.find('.variable-type').html((typeName ? typeName + '-type ' : ''));
if (trail) {
row.find('.variable-path').html((tempScope ? "_" : "$") + escape(trail));
}
row.find('.variable-name').html((!trail ? (tempScope ? "_" : "$") : '') + escape(name + ''));
row.find('.temporary-variable-scope').html(tempScope || '');
row.find('.variable-value').html(val);
row.find('tw-folddown')[folddown ? 'show' : 'hide']();
row.next('.panel-row-source td').html(folddown ? escape(toSource(value)) : '');
/*
So thart the .panel-row-source isn't considered unused and deleted, return it as well in the jQuery.
*/
return row.add(row.next('.panel-row-source'));
}
/*
Create the <span>s for the variable's name and value.
*/
......@@ -240,7 +258,7 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
"<td class='temporary-variable-scope'>" + (tempScope || '') + "</td>",
// Value
"<td class='variable-value'>" + val + "</td><td class='panel-row-buttons'>"
+ (folddown ? "<tw-folddown tabindex=0>(source:) </tw-folddown>" : '')
+ "<tw-folddown tabindex=0 style='display:" + (folddown ? "visible" : 'none') + "'>(source:) </tw-folddown>"
+ "</td>"
).add(
/*
......@@ -248,11 +266,11 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
A. it doesn't disrupt the :nth-of-type() styling used for variable rows.
B. it needs to hold a <td> with colspan, whose effect isn't available to CSS.
*/
folddown ? "<tr class='variable-row panel-row-source' style='display:none'><td colspan='5'>" + escape(toSource(value)) + "</td></tr>" : ""
"<tr class='variable-row panel-row-source' style='display:none'><td colspan='5'>" + (folddown ? escape(toSource(value)) : '') + "</td></tr>"
);
},
rowCheck({name, path, tempScope}, row) {
return row.attr('data-name') === name && row.attr('data-path') === (path+'');
return row.attr('data-name') === name && row.attr('data-path') === (path+'') && row.attr('data-scope') === tempScope;
},
columnHead() {
return `<tr class="panel-head"><th>Type</th><th>Name</th><th>Scope</th><th>Value</th></tr>`;
......@@ -402,7 +420,7 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
*/
const Enchantments = Panel.create({
className: "enchantments", tabName: "Enchantment",
rowAdd(enchantment) {
rowWrite(enchantment, row) {
const {scope, changer, name, localHook} = enchantment;
let val;
if (changer) {
......@@ -411,11 +429,18 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
else {
val = "<em>enchanted via (" + name + ":)</em>";
}
/*
Enchantment rows never need to be freshened up because rowCheck() compares
the exact enchantment object, from which all the values are derived.
*/
if (row) {
return row;
}
/*
Create the <span>s for the variable's name and value.
*/
return $('<div class="enchantment-row">')
.data('enchantment',enchantment)
.data('enchantment', enchantment)
.append(
"<td><span class='enchantment-name'>" + toSource(scope)
+ (localHook ? "</span><span class=enchantment-local>"
......@@ -459,8 +484,15 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
const storyletSection = Section.create(storyElement);
const Storylets = Panel.create({
className: "storylets", tabName: "Storylet",
rowAdd({name, active, storyletSource, exclusive, urgent}) {
rowWrite({name, active, storyletSource, exclusive, urgent}, row) {
if (row) {
/*
Only the active/inactive state needs to be updated.
*/
row[(!active ? 'add' : 'remove') + 'Class']('storylet-closed');
return row;
}
return $(`<tr class="storylet-row ${!active ? 'storylet-closed' : ''}">`)
.attr('data-name', name)
/*
......@@ -527,11 +559,11 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
Source
------
panel. This simply holds one "row" that's manually updated without using the same Panel
update -> rowCheck -> rowAdd lifecycle as the other panels.
update -> rowCheck -> rowWrite lifecycle as the other panels.
*/
const Source = Panel.create({
className: "source", tabName: "Source",
rowAdd: $.noop,
rowWrite: $.noop,
rowCheck: $.noop,
tabUpdate: $.noop,
columnHead: $.noop,
......@@ -551,9 +583,12 @@ define(['jquery', 'utils', 'state', 'internaltypes/varref', 'internaltypes/twine
*/
const Errors = Panel.create({
className: "errors", tabName: "Error",
rowAdd: $.noop,
rowWrite: $.noop,
rowCheck: $.noop,
columnHead: $.noop,
tabUpdate: count =>
Errors.tab.css({ background: count ? 'rgba(230,101,204,0.3)' : '' })
.text(`${count} Error${count !== 1 ? 's' : ''}`),
});
const onError = (error, code) => {
/*
......
......@@ -6,12 +6,13 @@ define(['jquery'], ($) => {
*/
const Panel = Object.freeze({
/*
rowAdd is a function which produces a new DOM structure representing the passed-in data.
rowCheck compares an existing DOM structure created by rowAdd to a given data row, to see if the
rowWrite is a function which produces a new DOM structure representing the passed-in data, or freshens up
an existing row if passed in
rowCheck compares an existing DOM structure created by rowWrite to a given data row, to see if the
former represents the latter.
tabUpdate is an overridable function for updating the tab's name.
*/
create({className, rowAdd, rowCheck, columnHead, tabName, tabUpdate}) {
create({className, rowWrite, rowCheck, columnHead, tabName, tabUpdate}) {
const panel = $(`<div class='panel panel-${className}' hidden><table class='panel-rows'></table></div>`);
const tab = $(`<button class='tab tab-${className}'>0 ${tabName}s</button>`);
tab.click(() => {
......@@ -33,14 +34,14 @@ define(['jquery'], ($) => {
tab,
panel,
panelRows: panel.find('.panel-rows'),
rowAdd,
rowWrite,
rowCheck,
columnHead,
tabUpdate,
});
},
update(data, count) {
const {rowCheck, rowAdd, panelRows, columnHead} = this;
const {rowCheck, rowWrite, panelRows, columnHead} = this;
const newRows = [];
const children = panelRows.children();
/*
......@@ -50,16 +51,16 @@ define(['jquery'], ($) => {
*/
data.forEach(d => {
const existingRow = children.filter((_,e) => rowCheck(d,$(e)));
const newRow = rowAdd(d);
if (existingRow.length) {
existingRow.replaceWith(newRow);
}
else {
const newRow = rowWrite(d, existingRow.length && existingRow);
if (!existingRow.length) {
panelRows.append(newRow);
}
newRows.push(newRow[0]);
newRows.push(...newRow.get());
});
children.filter((_,e) => !newRows.includes(e)).remove();
/*
Remove rows once their data is gone (but don't remove the table head).
*/
children.filter((_,e) => !newRows.includes(e) && !e.className.includes('panel-head')).remove();
/*
And finally, update the tab.
*/
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment