Commit 9d8da2b6 authored by Leon Arnott's avatar Leon Arnott
Browse files

Fixed yet more bugs.

 * Fixed a bug where giving a blank string as the Cancel button's label to (prompt:) or (confirm:) wouldn't cause the Cancel button to disappear.
 * Fixed a bug where (link-rerun:) behaved like (link-repeat:) when it was enchanted by (enchant:).
 * Fixed a bug where error messages would sometimes refer to temp variables named "all" as "all values of the temporary variables". The same applies to "any", "start", and "end".
 * Fixed a bug where hidden hooks and (hidden:) would suppress the effects of (hook:).
 * Fixed a bug where ...array-type (spread array-type) parameters to custom macros would unwittingly "flatten" the passed-in arrays, joining them all together.

Closes #222.
parent 765408ae6660
......@@ -19,6 +19,11 @@ Documentation is at http://twine2.neocities.org/. See below for compilation inst
* Fixed a bug where `(p-not:)` would not work correctly when given built-in datatypes like `alnum` or `digit`.
* Fixed a bug where the startup error dialog box (that reports certain kinds of Javascript errors) wouldn't appear.
* Fixed a bug where `(line-style:)`, `(enchant-in:)`, `(link-style:)` and `(char-style:)` did not work when used in an `(enchant:)` or `(change:)`. (However, they currently still don't work when created by a `via` lambda given to those command macros).
* Fixed a bug where giving a blank string as the Cancel button's label to `(prompt:)` or `(confirm:)` wouldn't cause the Cancel button to disappear.
* Fixed a bug where `(link-rerun:)` behaved like `(link-repeat:)` when it was enchanted by `(enchant:)`.
* Fixed a bug where error messages would sometimes refer to temp variables named "all" as "all values of the temporary variables". The same applies to "any", "start", and "end".
* Fixed a bug where hidden hooks and the `(hidden:)` changer would suppress the effects of `(hook:)`.
* Fixed a bug where `...array-type` parameters to custom macros would unwittingly "flatten" the passed-in arrays, joining them all together.
* Now, dataset data should be displayed correctly in the Variables panel in Debug Mode.
#### Alterations
......
......@@ -109,7 +109,11 @@ define(['jquery','utils/operationutils','internaltypes/changedescriptor', 'inter
Because each .set() activates the 'set' event for VarRef, which includes Debug Mode's
DOM updating, we need to only use .set() on the final iteration.
*/
const newArray = (tempVariables[name] || []).concat(arg);
const newArray = (tempVariables[name] || [])
/*
Don't accidentally spread arg if it's an array.
*/
.concat([arg]);
if (argIndex < args.length-1) {
tempVariables[name] = newArray;
return;
......
......@@ -324,7 +324,12 @@ define(['jquery', 'utils', 'renderer', 'datatypes/hookset'], ($, {assertOnlyHas,
followed by (show:?a) should result in ?a appearing, instead of nothing happening. (And
(show:?b) shouldn't do anything, either.)
*/
ChangeDescriptor.create({target,data:assign({}, data, {originalSource:source, hidden:true})}).update();
ChangeDescriptor.create({target,
/*
In the hidden hook, preserve HTML attributes (which includes 'name') but exclude 'style'.
*/
attr: this.attr.filter(e => !('style' in e)),
data: assign({}, data, {originalSource:source, hidden:true})}).update();
return $();
}
......
......@@ -73,7 +73,7 @@ define(['jquery', 'utils', 'internaltypes/changedescriptor', 'datatypes/changerc
}
else if (!ChangerCommand.isPrototypeOf(changer)) {
e.replaceWith(TwineError.create("macrocall",
"The 'via' lambda given to (enchant:) must return a changer, not " + objectName(changer) + "."
"The 'via' lambda given to enchantment macros must return a changer, not " + objectName(changer) + "."
).render(""));
lambda = changer = null;
}
......@@ -86,7 +86,7 @@ define(['jquery', 'utils', 'internaltypes/changedescriptor', 'datatypes/changerc
So, instead, the first item in the scope to produce an error gets replaced by it, and the rest of the scope is ignored.
*/
e.replaceWith(TwineError.create("macrocall",
"The changer produced by the 'via' lambda given to (enchant:) can't include a revision or enchantment changer like (replace:) or (click:)."
"The changer produced by the 'via' lambda given to enchantment macros can't include a revision or enchantment changer like (replace:) or (click:)."
).render(""));
lambda = changer = null;
}
......
......@@ -315,7 +315,7 @@ define(['state', 'internaltypes/twineerror', 'utils', 'utils/operationutils', 'd
|| VarRefProto.isPrototypeOf(obj)) {
return obj.get(prop);
}
if (prop === "any" || prop === "all" || prop === "start" || prop === "end") {
if ((prop === "any" || prop === "all" || prop === "start" || prop === "end") && !obj.TwineScript_VariableStoreName) {
return createDeterminer(obj,prop);
}
/*
......
......@@ -3031,11 +3031,11 @@ define(['jquery', 'macros', 'utils', 'state', 'passages', 'renderer', 'engine',
name: confirmButton || "OK",
confirm: true,
callback: () => section.unblock(d.find('input').last().val()),
},{
}].concat(cancelButton === "" ? [] : {
name: cancelButton || "Cancel",
cancel: true,
callback: () => section.unblock(defaultValue),
}],
}),
});
// Regrettably, this arbitrary timeout seems to be the only reliable way to focus the <input>.
setTimeout(() => d.find('input').last().focus(), 100);
......@@ -3090,11 +3090,11 @@ define(['jquery', 'macros', 'utils', 'state', 'passages', 'renderer', 'engine',
name: confirmButton || "OK",
confirm: true,
callback: () => section.unblock(true),
},{
}].concat(cancelButton === "" ? [] : {
name: cancelButton || "Cancel",
cancel: true,
callback: () => section.unblock(false),
}],
}),
});
},
[String, optional(String), optional(String)])
......
......@@ -412,22 +412,29 @@ define(['jquery', 'macros', 'utils', 'state', 'passages', 'engine', 'datatypes/c
the link, so that the replacement can be repeated. It does this by removing the link,
then reattaching it after rendering.
*/
let parent = link.parent();
let parent = link.parentsUntil(':not(tw-enchantment)').parent();
if (!parent.length) {
parent = link.parent();
}
if (name === "link-rerun") {
/*
Just to be sure that the link returns to the same DOM element, we
save the element in particular here.
In addition to detaching the link, this removes the <tw-enchantment>s surrounding the link.
*/
const p = link.parentsUntil(':not(tw-enchantment)');
link.detach();
p.remove();
}
/*
Only (link-replace:) and (link-rerun:) remove the link on click - the others merely append.
*/
if (name === "link" || name === "link-rerun" || name === "click-block") {
if (name === "link" || name === "link-rerun") {
parent.empty();
}
desc.section.renderInto("", null, desc, tempVariables);
if (name === "link-rerun") {
/*
If ?Link is enchanted, reinserting just the link will result in the <tw-enchantment>s being reinstated.
*/
parent.prepend(link);
}
},
......
......@@ -122,6 +122,9 @@ describe("control flow macros", function() {
it("can be composed with other style macros", function() {
expect("(set: $a to (hidden:) + (text-style:'bold'))$a[Gee]").markupToPrint("");
});
it("can be composed with (hook:)", function() {
expect("(set: $a to (hidden:) + (hook:'foo'))$a[Bar](show:?foo)").markupToPrint("Bar");
});
});
describe("the (show:) macro", function() {
it("accepts 1 or more hooknames", function() {
......
......@@ -168,6 +168,12 @@ describe("link macros", function() {
expect(p.text()).toBe("ABBB");
expect("$c").markupToPrint("36");
});
it("works when enchanted", function() {
var p = runPassage("(enchant:?link,(bg:blue))(set:$c to 0)("+name+":'A')[B(set:$c to it + 12)]");
p.find('tw-link').click().click().click();
expect(p.text()).toBe("ABBB");
expect("$c").markupToPrint("36");
});
} else {
it("when clicked multiple times, the hook is re-ran", function() {
var p = runPassage("(set:$c to 0)("+name+":'A')[B(set:$c to it + 12)]");
......@@ -175,6 +181,12 @@ describe("link macros", function() {
expect(p.text()).toBe("AB");
expect("$c").markupToPrint("36");
});
it("works when enchanted", function() {
var p = runPassage("(enchant:?link,(bg:blue))(set:$c to 0)("+name+":'A')[B(set:$c to it + 12)]");
p.find('tw-link').click().click().click();
expect(p.text()).toBe("AB");
expect("$c").markupToPrint("36");
});
}
it("can be altered with the optional style changer", function(done) {
var p = runPassage("("+name+":'mire', (text-rotate: 20))[]");
......
......@@ -335,6 +335,11 @@ describe("basic command macros", function() {
expect($("tw-dialog tw-link").first().text()).toBe("bar");
expect($("tw-dialog tw-link").last().text()).toBe("foo");
});
it("removes the Cancel button if its text is blank", function() {
runPassage("("+name+":" + args + ",'','foo')");
expect($("tw-dialog tw-link").length).toBe(1);
expect($("tw-dialog tw-link").first().text()).toBe("foo");
});
it("errors if the last optional string is blank", function() {
expect("("+name+":" + args + ",'foo','')").markupToError();
});
......
......@@ -31,6 +31,7 @@ describe("custom macros", function() {
beforeEach(function(){
runPassage("(set: $m to (macro:num-type _e, [(output-data:_e+10)]))");
runPassage("(set: $n to (macro:...num-type _e, [(output-data:_e)]))");
runPassage("(set: $o to (macro:...array-type _e, [(output-data:_e)]))");
});
it("are called by writing a macro call with their variable in place of the name, and supplying arguments", function() {
expect("($m:5)").markupToPrint("15");
......@@ -45,9 +46,11 @@ describe("custom macros", function() {
});
it("values given to spread parameters become arrays", function() {
expect("(print:array matches ($n:1,2,3,4,5))").markupToPrint('true');
expect("(print:(a:(a:1,2),(a:2,3)) is ($o:(a:1,2),(a:2,3)))").markupToPrint('true');
});
it("giving no values to spread parameters produces an empty array", function() {
expect("(print:array matches ($n:))").markupToPrint('true');
expect("(print:(a:) is ($o:))").markupToPrint('true');
});
it("supplying the wrong type of arguments produces an error", function() {
expect("($m:'e')").markupToError();
......
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