The following js code takes a snapshot of the active document prior to doing anything and reverts to that snapshot as part of the error handling process. It handles prior snapshots in the active document fine but it does assume that there are no further snapshots taken within the script (obviously this is easily adjusted for if necessary).
I was unable to find a scripted way to take the snapshot itself, hence the use of SL code for function takeSnapshot ().
Code: Select allvar originalRulerUnits = preferences.rulerUnits;
preferences.rulerUnits = Units.PERCENT;
function takeSnapshot ()
{
var id686 = charIDToTypeID( "Mk " );
var desc153 = new ActionDescriptor();
var id687 = charIDToTypeID( "null" );
var ref119 = new ActionReference();
var id688 = charIDToTypeID( "SnpS" );
ref119.putClass( id688 );
desc153.putReference( id687, ref119 );
var id689 = charIDToTypeID( "From" );
var ref120 = new ActionReference();
var id690 = charIDToTypeID( "HstS" );
var id691 = charIDToTypeID( "CrnH" );
ref120.putProperty( id690, id691 );
desc153.putReference( id689, ref120 );
executeAction( id686, desc153, DialogModes.NO );
}
function revertToLastSnapshot()
{
var docRef = app.activeDocument;
var hsObj = docRef.historyStates;
var hsLength = hsObj.length;
for (var i=hsLength - 1;i>-1;i--)
{
if(hsObj.snapshot) {
docRef.activeHistoryState = hsObj.getByName('Snapshot ' + i);
break;
}
}
}
function main ()
{
takeSnapshot(); // the position of this is critical and can vary
// the following is simply to test the process-------------------
app.activeDocument.artLayers.add();
app.activeDocument.activeLayer.name = 'Test Layer';
alert('Note the new layer "Test Layer"');
throw('TESTING\n\nThe Layer "Test Layer" should have been removed');
// end of test----------------------------------------------------
}
try
{
main();
}
catch (e)
{
revertToLastSnapshot();
alert('Script Error\n\n' + e);
}
finally
{
preferences.rulerUnits = originalRulerUnits;
}
Andrew
On Script Error Revert Image to State Prior to Script
On Script Error Revert Image to State Prior to Script
I've added your Snapshot code to my set of tools, with some minor edits. I've gotten in the habit of compressing script listener output to make it a bit more readable. Also, the way you had the interior of you loop made it a little non-obvious to me. I had to read it a couple of times to understand what you were doing. A slight change simplified it for me.
Thanks for the code.
Code: Select allfunction cTID(s) { return app.charIDToTypeID(s); }
function takeSnapshot ()
{
var desc = new ActionDescriptor(); // Make
var sref = new ActionReference(); // Snapshot
sref.putClass(cTID("SnpS"));
desc.putReference(cTID("null"), sref);
var fref = new ActionReference(); // From current history state
fref.putProperty(cTID("HstS"), cTID("CrnH"));
desc.putReference(cTID("From"), fref );
executeAction(cTID("Mk "), desc, DialogModes.NO );
}
function revertToLastSnapshot()
{
var docRef = app.activeDocument;
var hsObj = docRef.historyStates;
var hsLength = hsObj.length;
for (var i=hsLength - 1;i>-1;i--)
{
if (hsObj.snapshot) {
docRef.activeHistoryState = docRef.historyStates.getByName('Snapshot ' + i);
break;
}
}
}
Thanks for the code.
Code: Select allfunction cTID(s) { return app.charIDToTypeID(s); }
function takeSnapshot ()
{
var desc = new ActionDescriptor(); // Make
var sref = new ActionReference(); // Snapshot
sref.putClass(cTID("SnpS"));
desc.putReference(cTID("null"), sref);
var fref = new ActionReference(); // From current history state
fref.putProperty(cTID("HstS"), cTID("CrnH"));
desc.putReference(cTID("From"), fref );
executeAction(cTID("Mk "), desc, DialogModes.NO );
}
function revertToLastSnapshot()
{
var docRef = app.activeDocument;
var hsObj = docRef.historyStates;
var hsLength = hsObj.length;
for (var i=hsLength - 1;i>-1;i--)
{
if (hsObj.snapshot) {
docRef.activeHistoryState = docRef.historyStates.getByName('Snapshot ' + i);
break;
}
}
}
On Script Error Revert Image to State Prior to Script
Thanks Xbytor, I modified the loop along your lines.
Andrew
Andrew
On Script Error Revert Image to State Prior to Script
BTW maybe you can help me with something. In the Core Javascript Guide it says:
Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object. Any object whose value is not undefined, null, zero, NaN, or the empty string, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement. For example:
var b = new Boolean(false);
if (b) // this condition evaluates to true
Yet (and 'b' is indeed still typeof boolean):
var b = false;
if (b) // evaluates false
What is going on here. Because of my uncertainty I always use the if(somevar == true) form rather than if(somevar).
Andrew
Do not confuse the primitive Boolean values true and false with the true and false values of the Boolean object. Any object whose value is not undefined, null, zero, NaN, or the empty string, including a Boolean object whose value is false, evaluates to true when passed to a conditional statement. For example:
var b = new Boolean(false);
if (b) // this condition evaluates to true
Yet (and 'b' is indeed still typeof boolean):
var b = false;
if (b) // evaluates false
What is going on here. Because of my uncertainty I always use the if(somevar == true) form rather than if(somevar).
Andrew
On Script Error Revert Image to State Prior to Script
Andrew wrote:var b = new Boolean(false);
if (b) // this condition evaluates to true[/i]
Yet (and 'b' is indeed still typeof boolean):
var b = false;
if (b) // evaluates false
What is going on here. Because of my uncertainty I always use the if(somevar == true) form rather than if(somevar).
Andrew
I rarely run across Boolean objects in JS. The only case I can recall off the top of my head is when you need to create a new object but you don't know at parse time what the type of the object is. An example would be:Code: Select allvar x = { name : "x", cls : Boolean, val : true }
var y = { name : "y", cls : Number, val : 123 }
var fields = [x, y];
var form = {};
for (var i = 0; i < fields.length; i++) {
var f = fields;
form[f.name] = f.cls(f.val); // call the obj constructor indirectly
}
This is a bit artificial but it should illustrate the point. And it also doesn't really call the constructor. I don't remember the syntax for doing this off the top of my head so just pretend that the constructor is actually getting called.
In general, the boolean vs Boolean problem is not that much of a problem because you only run across Boolean objects in very special situations.
The reason that "new Boolean(false)" evaluates to true is that the expression returns an object reference, and a valid object reference always evaluates to true. Note that the expression "Boolean(false)" does evaluate to false because it returns a boolean primitive instead of constructing a Boolean object.
In the expression "new Boolean(false) == false", the interpreter is actually doing a bit more work to determine what the left hand side (lhs) of the '==' is doing. Probably something like "Boolean(lhs != undefined && lhs.valueOf())".
if (b) // this condition evaluates to true[/i]
Yet (and 'b' is indeed still typeof boolean):
var b = false;
if (b) // evaluates false
What is going on here. Because of my uncertainty I always use the if(somevar == true) form rather than if(somevar).
Andrew
I rarely run across Boolean objects in JS. The only case I can recall off the top of my head is when you need to create a new object but you don't know at parse time what the type of the object is. An example would be:Code: Select allvar x = { name : "x", cls : Boolean, val : true }
var y = { name : "y", cls : Number, val : 123 }
var fields = [x, y];
var form = {};
for (var i = 0; i < fields.length; i++) {
var f = fields;
form[f.name] = f.cls(f.val); // call the obj constructor indirectly
}
This is a bit artificial but it should illustrate the point. And it also doesn't really call the constructor. I don't remember the syntax for doing this off the top of my head so just pretend that the constructor is actually getting called.
In general, the boolean vs Boolean problem is not that much of a problem because you only run across Boolean objects in very special situations.
The reason that "new Boolean(false)" evaluates to true is that the expression returns an object reference, and a valid object reference always evaluates to true. Note that the expression "Boolean(false)" does evaluate to false because it returns a boolean primitive instead of constructing a Boolean object.
In the expression "new Boolean(false) == false", the interpreter is actually doing a bit more work to determine what the left hand side (lhs) of the '==' is doing. Probably something like "Boolean(lhs != undefined && lhs.valueOf())".