// (c) Copyright 2007. Adobe Systems, Incorporated. All rights reserved.
// Written by Tom Ruark
// UI Design by Julie Meridian
/*
@@@BUILDINFO@@@ Script Events Manager.jsx 1.1.0.2
*/
/*
// BEGIN__HARVEST_EXCEPTION_ZSTRING
$$$/JavaScripts/ScriptEventsManager/Menu=Script Events Manager...
scriptevents
808034C2-162D-481B-88D4-B3EF294EDE42
// END__HARVEST_EXCEPTION_ZSTRING
*/
// enable double clicking from the Macintosh Finder or the Windows Explorer
#target photoshop
// debug level: 0-2 (0:disable, 1:break on error, 2:break at beginning)
// $.level = 0;
// debugger; // launch debugger on next line
// on localized builds we pull the $$$/Strings from a .dat file, see documentation for more details
$.localize = true;
var gOneTime = true; // for CS3 we don't need this helper flag
var gCustomFileIndex;
try {
gUniqueID = "// 8eabd3c5-dcb2-4967-8f4d-f40e2f20476a";
GlobalVariables();
GlobalStrings();
var gParams = new Parameters( GetDefaultParamsFile(), InitParams );
gParams.Load();
var gEvents = gParams.Get( 'events' );
var gExtraFiles = gParams.Get( 'extrafiles' );
var actionInfo = GetActionSetInfo();
var dlgMain = new Window( 'dialog' );
dlgMain.text = strTitle;
dlgMain.orientation = 'row';
dlgMain.alignChildren = 'top';
var grpLeft = dlgMain.add( 'group' );
grpLeft.orientation = 'column';
grpLeft.alignChildren = 'left';
var grpGrpLeft = grpLeft.add( 'group' );
grpGrpLeft.orientation = 'column';
grpGrpLeft.alignChildren = 'fill';
var cbEnabled = grpGrpLeft.add( 'checkbox' );
cbEnabled.text = strEnabled;
cbEnabled.helpTip = strEnabledHelp;
cbEnabled.value = app.notifiersEnabled;
var lbEvents = grpGrpLeft.add( 'listbox', undefined, undefined, {multiselect: true} );
lbEvents.preferredSize = [StrToIntWithDefault( strlbEventsWidth, 400 ), StrToIntWithDefault( strlbEventsHeight, 126 )]; // 7 rows
lbEvents.helpTip = strEventsHelp;
var pnlAdd = grpGrpLeft.add( 'panel' );
pnlAdd.orientation = 'column';
pnlAdd.alignChildren = 'left';
pnlAdd.alignment = 'fill';
var grpEvent = pnlAdd.add( 'group' );
grpEvent.orientation = 'row';
grpEvent.alignChildren = 'center';
var stEvent = grpEvent.add( 'statictext' );
stEvent.text = strEvent;
stEvent.helpTip = strEventHelp;
var ddEvent = grpEvent.add( 'dropdownlist' );
ddEvent.helpTip = strEventHelp;
var grpFile = pnlAdd.add( 'group' );
grpFile.alignChildren = 'center';
var rbFile = grpFile.add( 'radiobutton' );
rbFile.text = strScript;
rbFile.helpTip = strFileHelp;
var ddFile = grpFile.add( 'dropdownlist' );
ddFile.helpTip = strFileHelp;
var stDescription = pnlAdd.add( 'edittext', undefined, undefined, {multiline:true, readonly:true} );
stDescription.preferredSize.height = StrToIntWithDefault( strstDescription, 65 );
stDescription.text = strDescriptionText;
var grpAction = pnlAdd.add( 'group' );
grpAction.orientation = 'row';
grpAction.alignChildren = 'center';
var rbAction = grpAction.add( 'radiobutton' );
rbAction.text = strActionDialog + ":";
rbAction.helpTip = strActionHelp;
var ddSet = grpAction.add( 'dropdownlist' );
ddSet.helpTip = strActionHelp;
var ddAction = grpAction.add( 'dropdownlist' );
ddAction.preferredSize.width = 250;
ddAction.helpTip = strActionHelp;
var pnlRight = dlgMain.add( 'group' );
pnlRight.orientation = 'column';
pnlRight.alignChildren = 'fill';
var btnDone = pnlRight.add( 'button' );
btnDone.text = strDone;
var btnRemove = pnlRight.add( 'button' );
btnRemove.text = strRemove;
btnRemove.helpTip = strRemoveHelp;
var btnRemoveAll = pnlRight.add( 'button' );
btnRemoveAll.text = strRemoveAll;
btnRemoveAll.helpTip = strRemovAllHelp;
var btnEventAdd = pnlRight.add( 'button' );
btnEventAdd.text = strAdd;
btnEventAdd.helpTip = strAddHelp;
// end dialog layout
// auto layout is great but we need some modifications
dlgMain.onShow = function() {
var rightEdge = pnlAdd.bounds.right - pnlAdd.bounds.left - 20;
grpEvent.bounds.right = rightEdge;
grpFile.bounds.right = rightEdge;
grpAction.bounds.right = rightEdge;
ddEvent.bounds.right = rightEdge - grpEvent.bounds.left;
ddFile.bounds.right = rightEdge - grpEvent.bounds.left;
stDescription.bounds.left = ddFile.bounds.left + grpFile.bounds.left;
stDescription.bounds.right = ddFile.bounds.right + grpFile.bounds.left - this.spacing;
ddAction.bounds.right = rightEdge - grpEvent.bounds.left;
var btnHeight = btnEventAdd.bounds.height;
var lbEventsCenter = lbEvents.bounds.top + lbEvents.bounds.height / 2;
btnRemove.location.y = lbEventsCenter - btnRemove.size.height / 2;
btnRemoveAll.location.y = btnRemove.location.y + btnRemove.size.height + pnlAdd.spacing;
// buttons are usually smaller than dropdowns, the 2 adjusts accordingly
btnEventAdd.bounds.top = pnlAdd.bounds.top + pnlAdd.spacing + 2;
btnEventAdd.bounds.bottom = btnEventAdd.bounds.top + btnHeight;
pnlRight.bounds.bottom = btnEventAdd.bounds.bottom + pnlRight.spacing * 2;
}
btnDone.onClick = function() {
gParams.Save();
this.parent.parent.close(true);
}
dlgMain.defaultElement = btnDone;
dlgMain.cancelElement = btnDone;
gCustomEventIndex = UpdateEventDropDown( ddEvent );
ddEvent.onChange = function() {
if ( gCustomEventIndex == this.selection.index ) {
var newEvent = CreateNewEvent();
if ( undefined != newEvent ) {
gEvents.push( newEvent );
gCustomEventIndex = UpdateEventDropDown( this, true );
} else {
ddEvent.items[ gLastEventIndex ].selected = true;
}
} else {
gLastEventIndex = this.selection.index;
}
ddEvent.helpTip = ddEvent.items[ gLastEventIndex ].toString();
}
rbFile.onClick = function() {
ddSet.enabled = ! this.value;
ddAction.enabled = ! this.value;
rbAction.value = ! this.value;
ddFile.enabled = this.value;
rbFile.value = this.value;
stDescription.enabled = this.value;
if ( this.value ) {
ddFile.active = true;
}
}
rbAction.onClick = function() {
ddSet.enabled = this.value;
ddAction.enabled = this.value;
rbAction.value = this.value;
ddFile.enabled = ! this.value;
rbFile.value = ! this.value;
stDescription.enabled = ! this.value;
if ( this.value ) {
ddSet.active = true;
}
}
rbAction.value = false;
rbFile.value = true;
if ( actionInfo.length > 0 ) {
for ( var i = 0; i < actionInfo.length; i++ ) {
ddSet.add( "item", actionInfo[i].name );
}
ddSet.items[0].selected = true;
ddSet.onChange = function() {
ddAction.removeAll();
for ( var i = 0; i < actionInfo[ this.selection.index ].children.length; i++ ) {
ddAction.add( "item", actionInfo[ this.selection.index ].children[ i ].name );
}
if ( ddAction.items.length > 0 ) {
ddAction.items[0].selected = true;
}
ddSet.helpTip = ddSet.items[ ddSet.selection.index ].toString();
}
ddSet.onChange();
} else {
ddSet.enabled = false;
ddAction.enabled = false;
}
ddAction.onChange = function() {
ddAction.helpTip = ddAction.items[ ddAction.selection.index ].toString();
}
UpdateRemovePanel( lbEvents, btnRemove, btnRemoveAll );
btnRemove.onClick = function () {
if ( null != lbEvents && null != lbEvents.selection ) {
for ( var i = 0; i < lbEvents.selection.length; i++ ) {
if ( app.notifiers[ lbEvents.selection[ i ].index ].eventFile.name.substr( 0, strActionNotifier.length ) == strActionNotifier ) {
app.notifiers[ lbEvents.selection[ i ].index ].eventFile.remove();
}
app.notifiers[ lbEvents.selection[ i ].index ].remove();
var indexRemoved = lbEvents.selection[ i ].index;
lbEvents.remove( lbEvents.selection[ i ].index );
if ( 0 == app.notifiers.length ) {
UpdateForNoNotifiers();
} else {
if ( indexRemoved < 1 ) {
indexRemoved++;
}
lbEvents.items[ indexRemoved - 1 ].selected = true;
}
}
} else {
alert( strPleaseSelect );
}
dlgMain.defaultElement.active = true;
}
btnRemoveAll.onClick = function () {
for ( var i = 0; i < app.notifiers.length; i++ ) {
if ( app.notifiers[ i ].eventFile.name.substr( 0, strActionNotifier.length ) == strActionNotifier ) {
app.notifiers[ i ].eventFile.remove();
}
}
app.notifiers.removeAll();
lbEvents.removeAll();
UpdateForNoNotifiers();
dlgMain.defaultElement.active = true;
}
btnEventAdd.onClick = function () {
if ( true == rbFile.value ) {
AddFileNotifier( ddEvent, ddFile );
} else {
AddActionNotifier( ddEvent, ddSet, ddAction, lbEvents );
}
UpdateRemovePanel( lbEvents, btnRemove, btnRemoveAll );
dlgMain.defaultElement.active = true;
}
gCustomFileIndex = UpdateScriptsFileDropDown( ddFile );
ddFile.onChange = function () {
if ( gCustomFileIndex == this.selection.index ) {
var newFile = undefined;
do {
if ( "Windows" == File.fs ) {
newFile = File.openDialog( strSelectFile, strFileExtension );
} else {
newFile = File.openDialog( strSelectFile, MacJSFilter );
}
if ( null != newFile && ! newFile.exists ) {
alert( strPickAnExistingFile );
newFile = -1;
continue;
}
if ( null != newFile && ! IsJavaScriptExtension( newFile ) ) {
alert( strPickAFileWithAJavaScriptExtension );
newFile = -1;
continue;
}
} while ( -1 == newFile );
if ( null != newFile ) {
gCustomFileIndex = UpdateScriptsFileDropDown( ddFile, newFile );
} else {
ddFile.items[ gLastFileIndex ].selected = true;
}
} else {
gLastFileIndex = this.selection.index;
stDescription.text = this.selection.description;
}
ddFile.helpTip = ddFile.items[ gLastFileIndex ].toString();
}
cbEnabled.onClick = function() {
app.notifiersEnabled = this.value;
lbEvents.enabled = this.value;
pnlAdd.enabled = this.value;
btnEventAdd.enabled = this.value;
}
rbFile.onClick();
cbEnabled.onClick();
// in case we double clicked the file
app.bringToFront();
dlgMain.center();
dlgMain.show();
} // end try
catch( e ) {
if ( confirm( strBigError ) ) {
alert( e + " : on line " + e.line );
}
}
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// Function: GetActionSetInfo
// Usage: walk all the items in the action palette and record the action set
// names and all the action children
// Input:
// Return: the array of all the ActionData
///////////////////////////////////////////////////////////////////////////////
function GetActionSetInfo() {
var actionSetInfo = new Array();
var setCounter = 1;
while ( true ) {
var ref = new ActionReference();
ref.putIndex( gClassActionSet, setCounter );
var desc = undefined;
try { desc = executeActionGet( ref ); }
catch( e ) { break; }
var actionData = new ActionData();
if ( desc.hasKey( gKeyName ) ) {
actionData.name = desc.getString( gKeyName );
}
var numberChildren = 0;
if ( desc.hasKey( gKeyNumberOfChildren ) ) {
numberChildren = desc.getInteger( gKeyNumberOfChildren );
}
if ( numberChildren ) {
actionData.children = GetActionInfo( setCounter, numberChildren );
actionSetInfo.push( actionData );
}
setCounter++;
}
return actionSetInfo;
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetActionInfo
// Usage: used when walking through all the actions in the action set
// Input: action set index, number of actions in this action set
// Return: true or false, true if file or folder is to be displayed
///////////////////////////////////////////////////////////////////////////////
function GetActionInfo( setIndex, numChildren ) {
var actionInfo = new Array();
for ( var i = 1; i <= numChildren; i++ ) {
var ref = new ActionReference();
ref.putIndex( gClassAction, i );
ref.putIndex( gClassActionSet, setIndex );
var desc = undefined;
desc = executeActionGet( ref );
var actionData = new ActionData();
if ( desc.hasKey( gKeyName ) ) {
actionData.name = desc.getString( gKeyName );
}
var numberChildren = 0;
if ( desc.hasKey( gKeyNumberOfChildren ) ) {
numberChildren = desc.getInteger( gKeyNumberOfChildren );
}
actionInfo.push( actionData );
}
return actionInfo;
}
///////////////////////////////////////////////////////////////////////////////
// Function: ActionData
// Usage: this could be an action set or an action
// Input:
// Return: a new Object of ActionData
///////////////////////////////////////////////////////////////////////////////
function ActionData() {
this.name = "";
this.children = undefined;
this.toString = function () {
var strTemp = this.name;
if ( undefined != this.children ) {
for ( var i = 0; i < this.children.length; i++ ) {
strTemp += " " + this.children[i].toString();
}
}
return strTemp;
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: EventData
// Usage: Create a new Object for eventID and string
// Input: Descriptive name and value
// Return: EventData created
///////////////////////////////////////////////////////////////////////////////
function EventData( name, value, valueClass ) {
this.name = name;
this.value = value;
if ( undefined == valueClass )
this.valueClass = '';
else
this.valueClass = valueClass;
}
///////////////////////////////////////////////////////////////////////////////
// Function: InitParams
// Usage: Initialize my default parameter settings
// Input: Parameters object
// Return:
///////////////////////////////////////////////////////////////////////////////
function InitParams( inObject ) {
inObject['events'] = new Array();
inObject['events'].push( new EventData( strStartApplication, 'Ntfy' ) );
inObject['events'].push( new EventData( strNewDocument, 'Mk ', 'Dcmn' ) );
inObject['events'].push( new EventData( strOpenDocument, 'Opn ' ) );
inObject['events'].push( new EventData( strStartSaveDocument, 'save', 'saveBegin' ) );
inObject['events'].push( new EventData( strSaveDocument, 'save', 'saveSucceeded' ) );
inObject['events'].push( new EventData( strCloseDocument, 'Cls ' ) );
inObject['events'].push( new EventData( strPrintDocument, 'Prnt' ) );
inObject['events'].push( new EventData( strExportDocument, 'Expr' ) );
inObject['events'].push( new EventData( strAll, 'All ' ) );
/*
// Class IDs related to event make (new)
inObject['events'].push( new EventData( 'New Layer', 'Mk ', 'Lyr ' ) );
inObject['events'].push( new EventData( 'New Channel', 'Mk ', 'Chnl' ) );
inObject['events'].push( new EventData( 'New Path', 'Mk ', 'Path' ) );
inObject['events'].push( new EventData( 'New Text Layer', 'Mk ', 'TxLr' ) );
inObject['events'].push( new EventData( 'New Solid Color Layer', 'Mk ', 'solidColorLayer' ) );
inObject['events'].push( new EventData( 'New Gradient Layer', 'Mk ', 'gradientLayer' ) );
inObject['events'].push( new EventData( 'New Pattern Layer', 'Mk ', 'patternLayer' ) );
inObject['events'].push( new EventData( 'New Levels Layer', 'Mk ', 'Lvls' ) );
inObject['events'].push( new EventData( 'New Curves Layer', 'Mk ', 'Crvs' ) );
inObject['events'].push( new EventData( 'New Color Balance Layer', 'Mk ', 'ClrB' ) );
inObject['events'].push( new EventData( 'New Brightness Contrast Layer', 'Mk ', 'BrgC' ) );
inObject['events'].push( new EventData( 'New Hue Saturation Layer', 'Mk ', 'HStr' ) );
inObject['events'].push( new EventData( 'New Selective Color Layer', 'Mk ', 'SlcC' ) );
inObject['events'].push( new EventData( 'New Channel Mixer Layer', 'Mk ', 'ChnM' ) );
inObject['events'].push( new EventData( 'New Gradient Map Layer', 'Mk ', 'GdMp' ) );
inObject['events'].push( new EventData( 'New Photo Filter Layer', 'Mk ', 'photoFilter' ) );
inObject['events'].push( new EventData( 'New Invert Layer', 'Mk ', 'Invr' ) );
inObject['events'].push( new EventData( 'New Threshold Layer', 'Mk ', 'Thrs' ) );
inObject['events'].push( new EventData( 'New Posterize Layer', 'Mk ', 'Pstr' ) );
inObject['events'].push( new EventData( 'New Brush', 'Mk ', 'Brsh' ) );
inObject['events'].push( new EventData( 'New Snapshot', 'Mk ', 'SnpS' ) );
inObject['events'].push( new EventData( 'New Swatch', 'Mk ', 'Clrs' ) );
inObject['events'].push( new EventData( 'New Tool Preset', 'Mk ', 'toolPreset' ) );
inObject['events'].push( new EventData( 'New Guide', 'Mk ', 'Gd ' ) );
inObject['events'].push( new EventData( 'New Spot Color Channel', 'Mk ', 'SCch' ) );
inObject['events'].push( new EventData( 'New Group from Layers', 'Mk ', 'layerSection' ) );
inObject['events'].push( new EventData( 'New Comp', 'Mk ', 'compsClass' ) );
// generic make, this will get all makes
inObject['events'].push( new EventData( 'New Anything', 'Mk ' ) );
*/
/*
// Class IDs related to event select
inObject['events'].push( new EventData( 'Select Layer', 'slct', 'Lyr ' ) );
inObject['events'].push( new EventData( 'Select Channel', 'slct', 'Chnl' ) );
inObject['events'].push( new EventData( 'Select Document', 'slct', 'Dcmn' ) );
inObject['events'].push( new EventData( 'Select Path', 'slct', 'Path' ) );
// generic select, this will get all selects
inObject['events'].push( new EventData( 'Select Anything', 'slct' ) );
*/
/*
// Class IDs related to event delete
inObject['events'].push( new EventData( 'Delete Layer', 'Dlt ', 'Lyr ' ) );
inObject['events'].push( new EventData( 'Delete Channel', 'Dlt ', 'Chnl' ) );
inObject['events'].push( new EventData( 'Delete Path', 'Dlt ', 'Path' ) );
// generic delete, this will get all deletes
inObject['events'].push( new EventData( 'Delete Anything', 'Dlt ' ) );
*/
}
///////////////////////////////////////////////////////////////////////////////
// Function: GlobalVariables
// Usage: global action items that are reused
// Input:
// Return:
///////////////////////////////////////////////////////////////////////////////
function GlobalVariables() {
gClassActionSet = charIDToTypeID( 'ASet' );
gClassAction = charIDToTypeID( 'Actn' );
gKeyName = charIDToTypeID( 'Nm ' );
gKeyNumberOfChildren = charIDToTypeID( 'NmbC' );
}
///////////////////////////////////////////////////////////////////////////////
// Function: GlobalStrings
// Usage: add your strings here that should be localized via the Photoshop
// zstring table, all items here are global scope
// Input:
// Return:
///////////////////////////////////////////////////////////////////////////////
function GlobalStrings() {
strTitle = localize( '$$$/JavaScript/ScriptEventsManager/Title=Script Events Manager' );
strAdd = localize( '$$$/JavaScript/ScriptEventsManager/Add=&Add' );
strEvent = localize( '$$$/JavaScript/ScriptEventsManager/Event=Photoshop Event:' );
strScript = localize( '$$$/JavaScript/ScriptEventsManager/Script=&Script:' );
strOK = localize( '$$$/JavaScript/ScriptEventsManager/OK=OK' );
strDone = localize( '$$$/JavaScript/ScriptEventsManager/Done=&Done' );
strCancel = localize( '$$$/JavaScript/ScriptEventsManager/Cancel=Cancel' );
strRemove = localize( '$$$/JavaScript/ScriptEventsManager/Remove=&Remove' );
strRemoveAll = localize( '$$$/JavaScript/ScriptEventsManager/RemoveAll=Remo&ve All' );
strAction = localize( '$$$/JavaScript/ScriptEventsManager/Action=Action' );
strActionDialog = localize( '$$$/JavaScript/ScriptEventsManager/ActionDialog=A&ction' );
strScriptEventsFolder = localize( '$$$/JavaScript/ScriptEventsManager/Folder=/Presets/Scripts/Event Scripts Only/' );
strName = localize( '$$$/JavaScript/ScriptEventsManager/Name=Event Name:' );
strValue = localize( '$$$/JavaScript/ScriptEventsManager/Value=Descriptive Label:' );
strPleaseSelect = localize( '$$$/JavaScript/ScriptEventsManager/PleaseSelect=Please select an installed notifier to remove.' );
strActionNotifier = localize( '$$$/JavaScript/ScriptEventsManager/ActionNotifier=ActionNotifier' );
strBrowse = localize( '$$$/JavaScript/ScriptEventsManager/Browse=Browse' );
strAddEvent = localize( '$$$/JavaScript/ScriptEventsManager/AddEvent=Add an Event' );
strFileExtension = localize( '$$$/JavaScript/ScriptEventsManager/FileExtension=JavaScript Files: *.js*' );
strSelectFile = localize( '$$$/JavaScript/ScriptEventsManager/SelectFile=Select a JavaScript file' );
strBigError = localize( "$$$/JavaScript/ScriptEventsManager/BigError=Sorry, something major happened and I can't continue! Would you like to see more info?" );
strStartApplication = localize( '$$$/JavaScript/ScriptEventsManager/StartApplication=Start Application' );
strNewDocument = localize( '$$$/JavaScript/ScriptEventsManager/NewDocument=New Document' );
strOpenDocument = localize( '$$$/JavaScript/ScriptEventsManager/OpenDocument=Open Document' );
strStartSaveDocument = localize( '$$$/JavaScript/ScriptEventsManager/StartSaveDocument=Start Save Document' );
strSaveDocument = localize( '$$$/JavaScript/ScriptEventsManager/SaveDocument=Save Document' );
strCloseDocument = localize( '$$$/JavaScript/ScriptEventsManager/CloseDocument=Close Document' );
strPrintDocument = localize( '$$$/JavaScript/ScriptEventsManager/PrintDocument=Print Document' );
strExportDocument = localize( '$$$/JavaScript/ScriptEventsManager/ExportDocument=Export Document' );
strAll = localize( '$$$/JavaScript/ScriptEventsManager/All=Everything' );
strEventHelp = localize( '$$$/JavaScript/ScriptEventsManager/EventHelp=Select an event' );
strFileHelp = localize( '$$$/JavaScript/ScriptEventsManager/FileHelp=Select a JavaScript file' );
strActionHelp = localize( '$$$/JavaScript/ScriptEventsManager/ActionHelp=Select an action set and an action' );
strAddHelp = localize( '$$$/JavaScript/ScriptEventsManager/AddHelp=Click to add the event' );
strEventsHelp = localize( '$$$/JavaScript/ScriptEventsManager/EventsHelp=List of events currently enabled' );
strRemoveHelp = localize( '$$$/JavaScript/ScriptEventsManager/RemoveHelp=Click to remove the selected event' );
strRemovAllHelp = localize( '$$$/JavaScript/ScriptEventsManager/RemoveAllHelp=Click to remove all the events' );
strDescription = localize( '$$$/JavaScript/ScriptEventsManager/Description=Description' );
strDescriptionText = localize( '$$$/JavaScript/ScriptEventsManager/DescriptionText=Manage your events by adding and removing. Select different JavaScript files to get detailed descriptions.' );
strAddFilesError = localize( '$$$/JavaScript/ScriptEventsManager/AddFilesError=Use the Browse item to add JavaScript files to the list.' );
strEnterAValue = localize( '$$$/JavaScript/ScriptEventsManager/EnterAValue=Please enter a descriptive label.' );
strEnterAName = localize( '$$$/JavaScript/ScriptEventsManager/EnterAName=Please enter an event name.' );
strNotifierAlreadyInstalled = localize( '$$$/ScriptingSupport/Error/NotifierAlreadyInstalled=Notifier already installed' );
strError = localize( '$$$/JavaScript/ScriptEventsManager/Error=Error: ' );
strEnabled = localize( '$$$/JavaScript/ScriptEventsManager/Enabled=&Enable Events to Run Scripts/Actions:' );
strEnabledHelp = localize( '$$$/JavaScript/ScriptEventsManager/EnabledHelp=Enable or disable all notifiers' );
strCannotOpen = localize( '$$$/JavaScript/ScriptEventsManager/CannotOpen=Cannot open file to save ' );
strCannotWrite = localize( '$$$/JavaScript/ScriptEventsManager/CannotWrite=Cannot write to file ' );
strCannotUndefined = localize( '$$$/JavaScript/ScriptEventsManager/CannotUndefined=Cannot save, file name is undefined.' );
strNoScripts = localize( '$$$/JavaScript/ScriptEventsManager/NoScripts=no scripts/actions associated with events' );
strSeeDocs = localize( '$$$/JavaScript/ScriptEventsManager/SeeDocs=Any scriptable event can be entered here. See the Scripting Reference for the full list of Photoshop event names.' );
strPickAnExistingFile = localize( '$$$/JavaScript/ScriptEventsManager/PickAnExistingFile=Please select an existing file.' );
strPickAFileWithAJavaScriptExtension = localize( '$$$/JavaScript/ScriptEventsManager/PickAFileWithJavaScriptExtension=Please select a file with a JavaScript extension. ( js or jsx)' );
strlbEventsHeight = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/LBEventsHeight=126" );
strlbEventsWidth = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/LBEventsWidth=400" );
strstDescription = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/STDescription=65" );
stretName = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/ETName=200" );
stretValue = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/ETValue=200" );
}
///////////////////////////////////////////////////////////////////////////////
// Function: UpdateRemovePanel
// Usage: update the list box for all the installed notifiers
// Input: list box, remove button and remove all button
// Return:
// Note: This list box is sorted by the following rules.
// 1. Events are shown in the same order as the Event listbox
// 2. In alphabetical order for > 1 script/action per event
///////////////////////////////////////////////////////////////////////////////
function UpdateRemovePanel( lb, btn, btnAll ) {
if ( app.notifiers.length > 0 ) {
lb.removeAll();
var allEvents = new Array( app.notifiers.length );
for ( var i = 0; i < app.notifiers.length; i++ ) {
var niceName = app.notifiers[i].event;
for ( var b = 0; b < gEvents.length; b++ ) {
if ( gEvents[b].value == app.notifiers[i].event &&
gEvents[b].valueClass == app.notifiers[i].eventClass ) {
niceName = gEvents[b].name;
break;
}
}
var betterDescription = File.decode( app.notifiers[i].eventFile.name.toString() );
if ( true == app.notifiers[i].eventFile.alias ) {
betterDescription = File.decode( app.notifiers[i].eventFile.resolve().name.toString() );
}
var inFile = app.notifiers[i].eventFile;
inFile.open( "r" );
var firstLine = inFile.readln();
var splitUp = firstLine.split( ", " );
if ( 4 == splitUp.length && splitUp[ 0 ] == gUniqueID ) {
betterDescription = splitUp[ 3 ] + " " + strAction + " (" + splitUp[ 2 ] + ")";
}
inFile.close();
allEvents[ i ] = niceName + ": " + betterDescription;
}
allEvents.sort( EventSort );
for ( var i = 0; i < allEvents.length; i++ ) {
lbEvents.add( "item", allEvents[ i ] );
}
// this used to select the new item in the list
// now I have sorted them, how do I find the new one?
// i could remember the old list and mark each one at a time
// what about on start up?
lb.items[ lb.items.length - 1 ].selected = true;
btn.enabled = true;
btnAll.enabled = true;
} else {
UpdateForNoNotifiers();
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: UpdateEventDropDown
// Usage: Populate the drop down list with the events or add an event
// Input: drop down list to update, new event created
// Return: the index of the custom event menu item
///////////////////////////////////////////////////////////////////////////////
function UpdateEventDropDown( dd, newEvent ) {
var customIndex = 0;
if ( undefined == newEvent ) {
dd.removeAll();
for ( var i = 0; i < gEvents.length; i++ ) {
dd.add( "item", gEvents[i].name );
}
customIndex = dd.items.length + 1;
dd.add( "separator", "before custom" );
dd.add( "item", strAddEvent + "..." );
dd.items[0].selected = true;
} else {
customIndex = gCustomEventIndex;
if ( gCustomEventIndex == ( dd.items.length - 1 ) ) {
dd.add( "separator", "after custom" );
}
dd.add( "item", gEvents[ gEvents.length - 1 ].name );
dd.items[ dd.items.length - 1 ].selected = true;
}
return customIndex;
}
///////////////////////////////////////////////////////////////////////////////
// Function: CreateNewEvent
// Usage: pop another dialog to create a new event
// Input:
// Return: a new EventData object
///////////////////////////////////////////////////////////////////////////////
function CreateNewEvent() {
var newEvent;
var dlgNewEvent = new Window( 'dialog' );
dlgNewEvent.text = strAddEvent;
dlgNewEvent.orientation = 'row';
dlgNewEvent.alignChildren = 'top';
var grpLeft = dlgNewEvent.add( 'group' );
grpLeft.orientation = 'column';
grpLeft.alignChildren = 'right';
var grpName = grpLeft.add( 'group' );
grpName.orientation = 'row';
var stName = grpName.add( 'statictext' );
stName.text = strName;
var etName = grpName.add( 'edittext' );
etName.preferredSize.width = StrToIntWithDefault( stretName, 200 );
var grpValue = grpLeft.add( 'group' );
grpValue.orientation = 'row';
var stValue = grpValue.add( 'statictext' );
stValue.text = strValue;
var etValue = grpValue.add( 'edittext' );
etValue.preferredSize.width = StrToIntWithDefault( stretValue, 200 );
var grpMessage = grpLeft.add( 'group' );
grpMessage.orientation = 'row';
var pngI = grpMessage.add( "image", undefined, 'InfoIcon' );
var stDescription = grpMessage.add( 'statictext', undefined, undefined, {multiline:true} );
stDescription.text = strSeeDocs;
var pnlRight = dlgNewEvent.add( 'group' );
pnlRight.orientation = 'column';
pnlRight.alignChildren = 'fill';
var btnOk = pnlRight.add( 'button', undefined, strOK );
var btnCancel = pnlRight.add( 'button', undefined, strCancel );
dlgNewEvent.defaultElement = btnOk;
dlgNewEvent.cancelElement = btnCancel;
dlgNewEvent.center();
btnOk.onClick = function() {
if ( 0 == etName.text.length ) {
alert( strEnterAName );
return;
}
if ( 0 == etValue.text.length ) {
alert( strEnterAValue );
return;
}
dlgNewEvent.close( true );
}
if ( true == dlgNewEvent.show() ) {
var splitValue = etValue.text.split( "," );
newEvent = new EventData( etName.text, splitValue[0], splitValue[1] );
}
return newEvent;
}
///////////////////////////////////////////////////////////////////////////////
// Function: UpdateScriptsFileDropDown
// Usage: Update the scripts drop down list, on init of the dialog I pull the
// data from the presets/scripts/event scripts only folder
// if the user browses to a new file then add it and some separators
// Input: the drop down list to update, the file from the browse
// Return: the index of the browse menu item
///////////////////////////////////////////////////////////////////////////////
function UpdateScriptsFileDropDown( dd, newFile ) {
var customIndex = 0;
if ( undefined == newFile ) {
var allFiles = Folder( path + strScriptEventsFolder ).getFiles();
gScriptsFiles = new Array();
if ( allFiles.length > 0 ) {
dd.removeAll();
for ( var i = 0; i < allFiles.length; i++ ) {
if ( allFiles[i].name.substr( 0, strActionNotifier.length ) != strActionNotifier &&
IsJavaScriptExtension( allFiles[i] ) ) {
var dataForMenu = GetDescriptionAndMenuNameFromFile( allFiles[i] );
var menuItem = dd.add( "item", dataForMenu["Name"] );
menuItem.description = dataForMenu["Desc"];
gScriptsFiles.push( allFiles[i] );
}
}
}
if ( undefined != gExtraFiles ) {
for ( var i = 0; i < gExtraFiles.length; i++ ) {
var dataForMenu = GetDescriptionAndMenuNameFromFile( File( gExtraFiles[i] ) );
var menuItem = dd.add( "item", dataForMenu["Name"] );
menuItem.description = dataForMenu["Desc"];
gScriptsFiles.push( File( gExtraFiles[i] ) );
}
}
if ( dd.items.length > 0 ) {
dd.items[0].selected = true;
}
customIndex = dd.items.length + 1;
dd.add( "separator", "before custom" );
dd.add( "item", strBrowse + "..." );
} else {
customIndex = gCustomFileIndex;
if ( gCustomFileIndex == ( dd.items.length - 1 ) ) {
dd.add( "separator", "after custom" );
}
var dataForMenu = GetDescriptionAndMenuNameFromFile( newFile );
var menuItem = dd.add( "item", dataForMenu["Name"] );
menuItem.description = dataForMenu["Desc"];
dd.items[ dd.items.length - 1 ].selected = true;
gScriptsFiles.push( newFile );
if ( undefined == gExtraFiles ) {
gExtraFiles = new Array();
gParams.Set( 'extrafiles', gExtraFiles );
}
gExtraFiles.push( newFile.absoluteURI );
}
return customIndex;
}
///////////////////////////////////////////////////////////////////////////////
// Function: AddFileNotifier
// Usage: The add button was clicked, add the notifier from the drop downs
// Input: two drop down lists, event and file
// Return:
// Note: I have to adjust for the custom items and the separators
///////////////////////////////////////////////////////////////////////////////
function AddFileNotifier( edd, fdd ) {
try {
if ( null == fdd.selection && 0 == gScriptsFiles.length ) {
throw strAddFilesError;
}
var eventsIndex = edd.selection.index;
if ( eventsIndex > gCustomEventIndex ) {
eventsIndex -= 3;
}
var filesIndex = fdd.selection.index;
if ( filesIndex > gCustomFileIndex ) {
filesIndex -= 3;
}
app.notifiers.add( gEvents[ eventsIndex ].value, gScriptsFiles[ filesIndex ], gEvents[ eventsIndex ].valueClass );
}
catch( e ) {
alert( e );
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: AddActionNotifier
// Usage: Create a JavaScript file with the code to execute an action from
// an action set
// Input: three drop down lists, event, action set and action, and the events list box
// Return:
///////////////////////////////////////////////////////////////////////////////
function AddActionNotifier( edd, sdd, add, lb ) {
try {
var strLookingFor = edd.selection.toString() + ": " + add.selection.toString() + " " + strAction + " (" + sdd.selection.toString() + ")";
for ( var i = 0; i < lb.items.length; i++ ) {
if ( lb.items[i].toString() == strLookingFor ) {
throw ( strError + strNotifierAlreadyInstalled );
}
}
var uniqueFileName = CreateUniqueFileName( app.preferencesFolder.toString() + "/", strActionNotifier, ".jsx" );
var outFile = new File ( uniqueFileName );
var addStr = escape( add.selection.toString() );
addStr = encodeURI( addStr );
var sddStr = escape( sdd.selection.toString() );
sddStr = encodeURI( sddStr );
outFile.open( "w" );
outFile.writeln( gUniqueID + ", " + edd.selection.toString() + ", " + sdd.selection.toString() + ", " + add.selection.toString() );
outFile.writeln( "try {" );
outFile.writeln( " var actionStr = '" + addStr.toString() + "';" );
outFile.writeln( " actionStr = decodeURI( actionStr );" );
outFile.writeln( " actionStr = unescape( actionStr );" );
outFile.writeln( " var actionSetStr = '" + sddStr.toString() + "';" );
outFile.writeln( " actionSetStr = decodeURI( actionSetStr );" );
outFile.writeln( " actionSetStr = unescape( actionSetStr );" );
outFile.writeln( " doAction( actionStr, actionSetStr );" );
outFile.writeln( "}" );
outFile.writeln( "catch( e ) { }" );
outFile.close();
var eventsIndex = edd.selection.index;
if ( eventsIndex > gCustomEventIndex ) {
eventsIndex -= 3;
}
app.notifiers.add( gEvents[ eventsIndex ].value, outFile, gEvents[ eventsIndex ].valueClass );
}
catch( e ) {
alert( e );
}
}
///////////////////////////////////////////////////////////////////////////////
// Function: CreateUniqueFileName
// Usage: given a folder, file name and extenstion create a file with a unique
// file name
// Input: given a folder, file name and extenstion
// Return: the full path to the unique file
///////////////////////////////////////////////////////////////////////////////
function CreateUniqueFileName( inFolder, inFileName, inExtension ) {
var uniqueFileName = inFolder + inFileName + inExtension;
var fileNumber = 1;
while ( File( uniqueFileName ).exists ) {
uniqueFileName = inFolder + inFileName + "_" + fileNumber + inExtension;
fileNumber++;
}
return uniqueFileName;
}
///////////////////////////////////////////////////////////////////////////////
// Function: MacJSFilter
// Input: f, file or folder to check
// Return: true or false, true if file or folder is to be displayed
///////////////////////////////////////////////////////////////////////////////
function MacJSFilter( f )
{
var jsExtension = ".js";
var jsExtension2 = ".jsx";
var folderThatsAnApp = ".app"; // this doesn't cover all packages or bundles
var lCaseName = f.name;
lCaseName.toLowerCase();
if ( lCaseName.lastIndexOf( jsExtension ) == f.name.length - jsExtension.length )
return true;
else if ( lCaseName.lastIndexOf( jsExtension2 ) == f.name.length - jsExtension2.length )
return true;
else if ( lCaseName.lastIndexOf( folderThatsAnApp ) == f.name.length - folderThatsAnApp.length )
return false;
else if ( f instanceof Folder )
return true;
else
return false;
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetDescriptionAndMenuNameFromFile
// Usage: Return the descriptive text and the name for the menu dropdown from
// variables in the file. The default description "Desc" is strDescriptionText
// and the default menu "Name" is the file name.
// The description should be stored so this only gets called once per file.
// Input: file to read out a description, not an alias
// Output: Array of "Desc" and "Name" for each file
///////////////////////////////////////////////////////////////////////////////
function GetDescriptionAndMenuNameFromFile( inFile ) {
var result = new Array;
result["Desc"] = strDescriptionText;
var readFile = inFile;
if ( true == inFile.alias ) {
readFile = inFile.resolve();
}
result["Name"] = File.decode( readFile.name );
var searchStrings = [ "Desc", "Name" ];
if ( undefined != readFile ) {
if ( readFile.open( "r" ) ) {
var readLength = 1000;
if ( readFile.length < readLength ) {
readLength = readFile.length;
}
var readData = readFile.read( readLength );
readFile.close();
for ( var i = 0; i < searchStrings.length; i++ ) {
var stringStartNew = 'var beg' + searchStrings[i] + ' = "';
var stringEndNew = '" // end' + searchStrings[i];
var descriptionStart = readData.indexOf( stringStartNew, 0 ) + stringStartNew.length;
var descriptionEnd = readData.indexOf( stringEndNew, descriptionStart );
if ( descriptionStart != -1 && descriptionEnd != -1 && descriptionEnd > descriptionStart ) {
result[ searchStrings[i] ] = localize( readData.substr( descriptionStart, descriptionEnd - descriptionStart ) );
}
// really old backwards compatibility search
if ( result["Desc"] == strDescriptionText && searchStrings[i] == "Desc" ) {
var stringStartOld = '/** "';
var stringEndOld = '" **/';
var descriptionStart = readData.indexOf( stringStartOld, 0 ) + stringStartOld.length;
var descriptionEnd = readData.indexOf( stringEndOld, descriptionStart );
if ( descriptionStart != -1 && descriptionEnd != -1 && descriptionEnd > descriptionStart ) {
result[ searchStrings[i] ] = localize( readData.substr( descriptionStart, descriptionEnd - descriptionStart ) );
}
}
}
}
}
return result;
}
///////////////////////////////////////////////////////////////////////////////
// Function: IsJavaScriptExtension
// Usage: See if the file extension is .js or .jsx
// Input: file to check extension
// Output: true if extension is .js or .jsx, false otherwise
///////////////////////////////////////////////////////////////////////////////
function IsJavaScriptExtension( inFile ) {
var returnValue = false;
var realFileName = inFile.name;
if ( true == inFile.alias ) {
realFileName = inFile.resolve().name;
}
var splitFileName = realFileName.split( "." );
if ( splitFileName.length > 1 ) {
var lastDot = splitFileName.length - 1;
splitFileName[ lastDot ] = splitFileName[ lastDot ].toLowerCase();
if ( splitFileName[ lastDot ] == "js" || splitFileName[ lastDot ] == "jsx" ) {
returnValue = true;
}
}
return returnValue;
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetScriptNameForXML
// Usage: You can't save certain characters in xml, strip them here
// NOTE: This list is not complete
// Input:
// Output: The title stripped of characters bad for xml
///////////////////////////////////////////////////////////////////////////////
function GetScriptNameForXML () {
var scriptNameForXML = new String( strTitle );
var charsToStrip = Array( " ", "'", "." );
for (var a = 0; a < charsToStrip.length; a++ ) {
var nameArray = scriptNameForXML.split( charsToStrip[a] );
scriptNameForXML = "";
for ( var b = 0; b < nameArray.length; b++ ) {
scriptNameForXML += nameArray[b];
}
}
return scriptNameForXML;
}
///////////////////////////////////////////////////////////////////////////////
// Function: GetDefaultParamsFile
// Usage: Get the file where I store my default parameters
// Input: , global strTitle must be defined
// Output: Location of File of my parameters
///////////////////////////////////////////////////////////////////////////////
function GetDefaultParamsFile() {
return ( new File( app.preferencesFolder + "/" + strTitle + ".xml" ) );
}
///////////////////////////////////////////////////////////////////////////////
// Function: Parameters
// Usage: Object to load and save parameters to disk
// Input: inFileName is the path to the file, initRoutine will be called
// to create your default parameters
// Output: new object, use the Get(), Set(), Load() and Save() routines
// other routines are for private use by the object
///////////////////////////////////////////////////////////////////////////////
function Parameters( inFileName, initRoutine ) {
// functions for public use
this.Get = function ( index ) {
return this.data[index];
}
this.Set = function ( index, value ) {
this.data[index] = value;
}
this.Load = function ( ) {
if ( File( this.fileName ).exists ) {
var loadFile = File( this.fileName );
if ( loadFile.open( "r" ) ) {
var strXML = loadFile.read( loadFile.length );
loadFile.close();
var startSpace = strXML.indexOf( "<" ) + 1;
var endSpace = strXML.indexOf( ">" );
if ( endSpace == -1 ) return;
var projectSpace = strXML.substring( startSpace, endSpace );
if ( projectSpace == GetScriptNameForXML() ) {
strXML = strXML.substring( endSpace + 1, strXML.length );
this.ReadElements( strXML, this.data );
}
}
}
}
this.Save = function ( ) {
if ( undefined == this.fileName ) {
alert( strCannotUndefined );
return;
}
var saveFile = File( this.fileName );
saveFile.encoding = "UTF8";
if ( saveFile.open( "w", "TEXT", "????" ) ) {
if ( saveFile.write( "\uFEFF" ) ) {
saveFile.writeln( "<" + GetScriptNameForXML() + ">" );
this.WriteData( saveFile, this.data );
saveFile.writeln( "" + GetScriptNameForXML() + ">" );
saveFile.close();
} else {
alert( strCannotWrite + this.fileName.fsName );
saveFile.close();
return;
}
} else {
alert( strCannotOpen + this.fileName.fsName );
}
}
// functions for private use
this.Initialize = function( initRoutine ) {
if ( undefined != initRoutine ) {
initRoutine( this.data );
}
}
this.WriteData = function( inFile, inData ) {
this.tabLevel++;
var prop;
for ( prop in inData ) {
if ( typeof( inData[ prop ] ) == "object" ) {
this.WriteTabs( inFile, this.tabLevel );
inFile.writeln( "<" + prop + ">" );
this.WriteData( inFile, inData[ prop ] );
this.WriteTabs( inFile, this.tabLevel );
inFile.writeln( "" + prop + ">" );
} else {
this.WriteTabs( inFile, this.tabLevel );
inFile.writeln( "<" + prop + ">" + inData[ prop ] + "" + prop + ">" );
}
}
this.tabLevel--;
}
this.WriteTabs = function( inFile, tabs ) {
while ( tabs-- ) {
inFile.write( "\t" );
}
}
this.ReadElements = function( inText, inData ) {
while ( inText.length ) {
var startMarker = inText.indexOf( "<" ) + 1;
var endMarker = inText.indexOf( ">" );
if ( endMarker == -1 ) break;
var starter = inText.substring( startMarker, endMarker );
var enderIndex = inText.indexOf( "" + starter + ">" );
if ( enderIndex == -1 ) break;
var data = inText.substring( endMarker + 1, enderIndex );
if ( data.search( "<" ) != -1 ) {
inData[ starter ] = new Array();
this.ReadElements( data, inData[ starter ] );
} else {
inData[ starter ] = data;
}
// force boolean values to boolean types
if ( data == "true" || data == "false" ) {
inData[ starter ] = data == "true";
}
// should I force number values to numbers ???
inText = inText.substring( enderIndex + ("" + starter + ">" ).length, inText.length );
}
}
// internal variables, public should not access
this.fileName = inFileName;
this.data = new Array();
this.tabLevel = 0;
this.Initialize( initRoutine );
}
///////////////////////////////////////////////////////////////////////////////
// Function: UpdateForNoNotifiers
// Usage: set up the events list box for no events and disable the buttons
// Input: : globals btnRemove, btnRemoveAll, strNoScripts and lbEvents
// Return:
///////////////////////////////////////////////////////////////////////////////
function UpdateForNoNotifiers() {
btnRemove.enabled = false;
btnRemoveAll.enabled = false;
lbEvents.add( "item", strNoScripts );
}
///////////////////////////////////////////////////////////////////////////////
// Function: EventSort
// Usage: sort function for the events list box
// Input: a, b are the two events to sort
// Return: -1 or 1, no need for 0 as there should be no dupes
///////////////////////////////////////////////////////////////////////////////
function EventSort( a, b ) {
var aa = a.split( ":" );
if ( aa.length < 2 ) {
return -1;
}
var bb = b.split( ":" );
if ( bb.length < 2 ) {
return 1;
}
var aaIndex = 0;
var bbIndex = 0;
for ( var i = 0; i < ddEvent.items.length; i++ ) {
if ( ddEvent.items[ i ].toString() == aa[ 0 ] ) {
aaIndex = i;
}
if ( ddEvent.items[ i ].toString() == bb[ 0 ] ) {
bbIndex = i;
}
}
if ( bbIndex == aaIndex ) {
var cc = [ aa[ 1 ], bb[ 1 ] ];
cc.sort();
if ( cc[ 0 ] == aa[ 1 ] ) {
return -1;
} else {
return 1;
}
} else {
if ( aaIndex < bbIndex ) {
return -1;
} else {
return 1;
}
}
return -1;
}
///////////////////////////////////////////////////////////////////////////
// Function: StrToIntWithDefault
// Usage: convert a string to a number, first stripping all characters
// Input: string and a default number
// Return: a number
///////////////////////////////////////////////////////////////////////////
function StrToIntWithDefault( s, n ) {
var onlyNumbers = /[^0-9]/g;
var t = s.replace( onlyNumbers, "" );
t = parseInt( t );
if ( ! isNaN( t ) ) {
n = t;
}
return n;
}
// end Script Events Manager.jsx