· 8 years ago · Aug 13, 2018, 07:38 PM
1// (c) Copyright 2007. Adobe Systems, Incorporated. All rights reserved.
2// Written by Tom Ruark
3// UI Design by Julie Meridian
4
5/*
6@@@BUILDINFO@@@ Script Events Manager.jsx 1.1.0.2
7*/
8
9/*
10
11// BEGIN__HARVEST_EXCEPTION_ZSTRING
12
13<javascriptresource>
14<name>$$$/JavaScripts/ScriptEventsManager/Menu=Script Events Manager...</name>
15<category>scriptevents</category>
16<eventid>808034C2-162D-481B-88D4-B3EF294EDE42</eventid>
17</javascriptresource>
18
19// END__HARVEST_EXCEPTION_ZSTRING
20
21*/
22
23// enable double clicking from the Macintosh Finder or the Windows Explorer
24#target photoshop
25
26// debug level: 0-2 (0:disable, 1:break on error, 2:break at beginning)
27// $.level = 0;
28// debugger; // launch debugger on next line
29
30// on localized builds we pull the $$$/Strings from a .dat file, see documentation for more details
31$.localize = true;
32
33var gOneTime = true; // for CS3 we don't need this helper flag
34var gCustomFileIndex;
35
36try {
37
38 gUniqueID = "// 8eabd3c5-dcb2-4967-8f4d-f40e2f20476a";
39
40 GlobalVariables();
41
42 GlobalStrings();
43
44 var gParams = new Parameters( GetDefaultParamsFile(), InitParams );
45
46 gParams.Load();
47
48 var gEvents = gParams.Get( 'events' );
49
50 var gExtraFiles = gParams.Get( 'extrafiles' );
51
52 var actionInfo = GetActionSetInfo();
53
54 var dlgMain = new Window( 'dialog' );
55
56 dlgMain.text = strTitle;
57 dlgMain.orientation = 'row';
58 dlgMain.alignChildren = 'top';
59 var grpLeft = dlgMain.add( 'group' );
60 grpLeft.orientation = 'column';
61 grpLeft.alignChildren = 'left';
62 var grpGrpLeft = grpLeft.add( 'group' );
63 grpGrpLeft.orientation = 'column';
64 grpGrpLeft.alignChildren = 'fill';
65
66 var cbEnabled = grpGrpLeft.add( 'checkbox' );
67 cbEnabled.text = strEnabled;
68 cbEnabled.helpTip = strEnabledHelp;
69 cbEnabled.value = app.notifiersEnabled;
70
71 var lbEvents = grpGrpLeft.add( 'listbox', undefined, undefined, {multiselect: true} );
72 lbEvents.preferredSize = [StrToIntWithDefault( strlbEventsWidth, 400 ), StrToIntWithDefault( strlbEventsHeight, 126 )]; // 7 rows
73 lbEvents.helpTip = strEventsHelp;
74 var pnlAdd = grpGrpLeft.add( 'panel' );
75 pnlAdd.orientation = 'column';
76 pnlAdd.alignChildren = 'left';
77 pnlAdd.alignment = 'fill';
78 var grpEvent = pnlAdd.add( 'group' );
79 grpEvent.orientation = 'row';
80 grpEvent.alignChildren = 'center';
81 var stEvent = grpEvent.add( 'statictext' );
82 stEvent.text = strEvent;
83 stEvent.helpTip = strEventHelp;
84 var ddEvent = grpEvent.add( 'dropdownlist' );
85 ddEvent.helpTip = strEventHelp;
86 var grpFile = pnlAdd.add( 'group' );
87 grpFile.alignChildren = 'center';
88 var rbFile = grpFile.add( 'radiobutton' );
89 rbFile.text = strScript;
90 rbFile.helpTip = strFileHelp;
91 var ddFile = grpFile.add( 'dropdownlist' );
92 ddFile.helpTip = strFileHelp;
93
94 var stDescription = pnlAdd.add( 'edittext', undefined, undefined, {multiline:true, readonly:true} );
95 stDescription.preferredSize.height = StrToIntWithDefault( strstDescription, 65 );
96 stDescription.text = strDescriptionText;
97
98 var grpAction = pnlAdd.add( 'group' );
99 grpAction.orientation = 'row';
100 grpAction.alignChildren = 'center';
101 var rbAction = grpAction.add( 'radiobutton' );
102 rbAction.text = strActionDialog + ":";
103 rbAction.helpTip = strActionHelp;
104 var ddSet = grpAction.add( 'dropdownlist' );
105 ddSet.helpTip = strActionHelp;
106 var ddAction = grpAction.add( 'dropdownlist' );
107 ddAction.preferredSize.width = 250;
108 ddAction.helpTip = strActionHelp;
109 var pnlRight = dlgMain.add( 'group' );
110 pnlRight.orientation = 'column';
111 pnlRight.alignChildren = 'fill';
112 var btnDone = pnlRight.add( 'button' );
113 btnDone.text = strDone;
114 var btnRemove = pnlRight.add( 'button' );
115 btnRemove.text = strRemove;
116 btnRemove.helpTip = strRemoveHelp;
117 var btnRemoveAll = pnlRight.add( 'button' );
118 btnRemoveAll.text = strRemoveAll;
119 btnRemoveAll.helpTip = strRemovAllHelp;
120 var btnEventAdd = pnlRight.add( 'button' );
121 btnEventAdd.text = strAdd;
122 btnEventAdd.helpTip = strAddHelp;
123
124 // end dialog layout
125
126 // auto layout is great but we need some modifications
127 dlgMain.onShow = function() {
128
129 var rightEdge = pnlAdd.bounds.right - pnlAdd.bounds.left - 20;
130
131 grpEvent.bounds.right = rightEdge;
132 grpFile.bounds.right = rightEdge;
133 grpAction.bounds.right = rightEdge;
134
135 ddEvent.bounds.right = rightEdge - grpEvent.bounds.left;
136 ddFile.bounds.right = rightEdge - grpEvent.bounds.left;
137 stDescription.bounds.left = ddFile.bounds.left + grpFile.bounds.left;
138 stDescription.bounds.right = ddFile.bounds.right + grpFile.bounds.left - this.spacing;
139 ddAction.bounds.right = rightEdge - grpEvent.bounds.left;
140
141 var btnHeight = btnEventAdd.bounds.height;
142
143 var lbEventsCenter = lbEvents.bounds.top + lbEvents.bounds.height / 2;
144 btnRemove.location.y = lbEventsCenter - btnRemove.size.height / 2;
145 btnRemoveAll.location.y = btnRemove.location.y + btnRemove.size.height + pnlAdd.spacing;
146
147 // buttons are usually smaller than dropdowns, the 2 adjusts accordingly
148 btnEventAdd.bounds.top = pnlAdd.bounds.top + pnlAdd.spacing + 2;
149 btnEventAdd.bounds.bottom = btnEventAdd.bounds.top + btnHeight;
150
151 pnlRight.bounds.bottom = btnEventAdd.bounds.bottom + pnlRight.spacing * 2;
152 }
153
154 btnDone.onClick = function() {
155 gParams.Save();
156 this.parent.parent.close(true);
157 }
158
159 dlgMain.defaultElement = btnDone;
160 dlgMain.cancelElement = btnDone;
161
162 gCustomEventIndex = UpdateEventDropDown( ddEvent );
163
164 ddEvent.onChange = function() {
165 if ( gCustomEventIndex == this.selection.index ) {
166 var newEvent = CreateNewEvent();
167 if ( undefined != newEvent ) {
168 gEvents.push( newEvent );
169 gCustomEventIndex = UpdateEventDropDown( this, true );
170 } else {
171 ddEvent.items[ gLastEventIndex ].selected = true;
172 }
173 } else {
174 gLastEventIndex = this.selection.index;
175 }
176 ddEvent.helpTip = ddEvent.items[ gLastEventIndex ].toString();
177 }
178
179 rbFile.onClick = function() {
180 ddSet.enabled = ! this.value;
181 ddAction.enabled = ! this.value;
182 rbAction.value = ! this.value;
183 ddFile.enabled = this.value;
184 rbFile.value = this.value;
185 stDescription.enabled = this.value;
186 if ( this.value ) {
187 ddFile.active = true;
188 }
189 }
190
191 rbAction.onClick = function() {
192 ddSet.enabled = this.value;
193 ddAction.enabled = this.value;
194 rbAction.value = this.value;
195 ddFile.enabled = ! this.value;
196 rbFile.value = ! this.value;
197 stDescription.enabled = ! this.value;
198 if ( this.value ) {
199 ddSet.active = true;
200 }
201 }
202
203 rbAction.value = false;
204 rbFile.value = true;
205
206 if ( actionInfo.length > 0 ) {
207 for ( var i = 0; i < actionInfo.length; i++ ) {
208 ddSet.add( "item", actionInfo[i].name );
209 }
210 ddSet.items[0].selected = true;
211 ddSet.onChange = function() {
212 ddAction.removeAll();
213 for ( var i = 0; i < actionInfo[ this.selection.index ].children.length; i++ ) {
214 ddAction.add( "item", actionInfo[ this.selection.index ].children[ i ].name );
215 }
216 if ( ddAction.items.length > 0 ) {
217 ddAction.items[0].selected = true;
218 }
219 ddSet.helpTip = ddSet.items[ ddSet.selection.index ].toString();
220 }
221 ddSet.onChange();
222 } else {
223 ddSet.enabled = false;
224 ddAction.enabled = false;
225 }
226
227 ddAction.onChange = function() {
228 ddAction.helpTip = ddAction.items[ ddAction.selection.index ].toString();
229 }
230
231 UpdateRemovePanel( lbEvents, btnRemove, btnRemoveAll );
232
233 btnRemove.onClick = function () {
234 if ( null != lbEvents && null != lbEvents.selection ) {
235 for ( var i = 0; i < lbEvents.selection.length; i++ ) {
236 if ( app.notifiers[ lbEvents.selection[ i ].index ].eventFile.name.substr( 0, strActionNotifier.length ) == strActionNotifier ) {
237 app.notifiers[ lbEvents.selection[ i ].index ].eventFile.remove();
238 }
239 app.notifiers[ lbEvents.selection[ i ].index ].remove();
240 var indexRemoved = lbEvents.selection[ i ].index;
241 lbEvents.remove( lbEvents.selection[ i ].index );
242 if ( 0 == app.notifiers.length ) {
243 UpdateForNoNotifiers();
244 } else {
245 if ( indexRemoved < 1 ) {
246 indexRemoved++;
247 }
248 lbEvents.items[ indexRemoved - 1 ].selected = true;
249 }
250 }
251 } else {
252 alert( strPleaseSelect );
253 }
254 dlgMain.defaultElement.active = true;
255 }
256
257 btnRemoveAll.onClick = function () {
258 for ( var i = 0; i < app.notifiers.length; i++ ) {
259 if ( app.notifiers[ i ].eventFile.name.substr( 0, strActionNotifier.length ) == strActionNotifier ) {
260 app.notifiers[ i ].eventFile.remove();
261 }
262 }
263 app.notifiers.removeAll();
264 lbEvents.removeAll();
265 UpdateForNoNotifiers();
266 dlgMain.defaultElement.active = true;
267 }
268
269 btnEventAdd.onClick = function () {
270 if ( true == rbFile.value ) {
271 AddFileNotifier( ddEvent, ddFile );
272 } else {
273 AddActionNotifier( ddEvent, ddSet, ddAction, lbEvents );
274 }
275 UpdateRemovePanel( lbEvents, btnRemove, btnRemoveAll );
276 dlgMain.defaultElement.active = true;
277 }
278
279 gCustomFileIndex = UpdateScriptsFileDropDown( ddFile );
280
281 ddFile.onChange = function () {
282 if ( gCustomFileIndex == this.selection.index ) {
283 var newFile = undefined;
284 do {
285 if ( "Windows" == File.fs ) {
286 newFile = File.openDialog( strSelectFile, strFileExtension );
287 } else {
288 newFile = File.openDialog( strSelectFile, MacJSFilter );
289 }
290 if ( null != newFile && ! newFile.exists ) {
291 alert( strPickAnExistingFile );
292 newFile = -1;
293 continue;
294 }
295 if ( null != newFile && ! IsJavaScriptExtension( newFile ) ) {
296 alert( strPickAFileWithAJavaScriptExtension );
297 newFile = -1;
298 continue;
299 }
300 } while ( -1 == newFile );
301 if ( null != newFile ) {
302 gCustomFileIndex = UpdateScriptsFileDropDown( ddFile, newFile );
303 } else {
304 ddFile.items[ gLastFileIndex ].selected = true;
305 }
306 } else {
307 gLastFileIndex = this.selection.index;
308 stDescription.text = this.selection.description;
309 }
310 ddFile.helpTip = ddFile.items[ gLastFileIndex ].toString();
311 }
312
313 cbEnabled.onClick = function() {
314 app.notifiersEnabled = this.value;
315 lbEvents.enabled = this.value;
316 pnlAdd.enabled = this.value;
317 btnEventAdd.enabled = this.value;
318 }
319
320 rbFile.onClick();
321
322 cbEnabled.onClick();
323
324 // in case we double clicked the file
325 app.bringToFront();
326
327 dlgMain.center();
328
329 dlgMain.show();
330
331} // end try
332
333catch( e ) {
334 if ( confirm( strBigError ) ) {
335 alert( e + " : on line " + e.line );
336 }
337}
338
339
340///////////////////////////////////////////////////////////////////////////////
341///////////////////////////////////////////////////////////////////////////////
342///////////////////////////////////////////////////////////////////////////////
343///////////////////////////////////////////////////////////////////////////////
344///////////////////////////////////////////////////////////////////////////////
345
346
347///////////////////////////////////////////////////////////////////////////////
348// Function: GetActionSetInfo
349// Usage: walk all the items in the action palette and record the action set
350// names and all the action children
351// Input: <none>
352// Return: the array of all the ActionData
353///////////////////////////////////////////////////////////////////////////////
354function GetActionSetInfo() {
355 var actionSetInfo = new Array();
356 var setCounter = 1;
357 while ( true ) {
358 var ref = new ActionReference();
359 ref.putIndex( gClassActionSet, setCounter );
360 var desc = undefined;
361 try { desc = executeActionGet( ref ); }
362 catch( e ) { break; }
363 var actionData = new ActionData();
364 if ( desc.hasKey( gKeyName ) ) {
365 actionData.name = desc.getString( gKeyName );
366 }
367 var numberChildren = 0;
368 if ( desc.hasKey( gKeyNumberOfChildren ) ) {
369 numberChildren = desc.getInteger( gKeyNumberOfChildren );
370 }
371 if ( numberChildren ) {
372 actionData.children = GetActionInfo( setCounter, numberChildren );
373 actionSetInfo.push( actionData );
374 }
375 setCounter++;
376 }
377 return actionSetInfo;
378}
379
380
381///////////////////////////////////////////////////////////////////////////////
382// Function: GetActionInfo
383// Usage: used when walking through all the actions in the action set
384// Input: action set index, number of actions in this action set
385// Return: true or false, true if file or folder is to be displayed
386///////////////////////////////////////////////////////////////////////////////
387function GetActionInfo( setIndex, numChildren ) {
388 var actionInfo = new Array();
389 for ( var i = 1; i <= numChildren; i++ ) {
390 var ref = new ActionReference();
391 ref.putIndex( gClassAction, i );
392 ref.putIndex( gClassActionSet, setIndex );
393 var desc = undefined;
394 desc = executeActionGet( ref );
395 var actionData = new ActionData();
396 if ( desc.hasKey( gKeyName ) ) {
397 actionData.name = desc.getString( gKeyName );
398 }
399 var numberChildren = 0;
400 if ( desc.hasKey( gKeyNumberOfChildren ) ) {
401 numberChildren = desc.getInteger( gKeyNumberOfChildren );
402 }
403 actionInfo.push( actionData );
404 }
405 return actionInfo;
406}
407
408
409///////////////////////////////////////////////////////////////////////////////
410// Function: ActionData
411// Usage: this could be an action set or an action
412// Input: <none>
413// Return: a new Object of ActionData
414///////////////////////////////////////////////////////////////////////////////
415function ActionData() {
416 this.name = "";
417 this.children = undefined;
418 this.toString = function () {
419 var strTemp = this.name;
420 if ( undefined != this.children ) {
421 for ( var i = 0; i < this.children.length; i++ ) {
422 strTemp += " " + this.children[i].toString();
423 }
424 }
425 return strTemp;
426 }
427}
428
429
430///////////////////////////////////////////////////////////////////////////////
431// Function: EventData
432// Usage: Create a new Object for eventID and string
433// Input: Descriptive name and value
434// Return: EventData created
435///////////////////////////////////////////////////////////////////////////////
436function EventData( name, value, valueClass ) {
437 this.name = name;
438 this.value = value;
439 if ( undefined == valueClass )
440 this.valueClass = '';
441 else
442 this.valueClass = valueClass;
443}
444
445
446///////////////////////////////////////////////////////////////////////////////
447// Function: InitParams
448// Usage: Initialize my default parameter settings
449// Input: Parameters object
450// Return: <none>
451///////////////////////////////////////////////////////////////////////////////
452function InitParams( inObject ) {
453 inObject['events'] = new Array();
454 inObject['events'].push( new EventData( strStartApplication, 'Ntfy' ) );
455 inObject['events'].push( new EventData( strNewDocument, 'Mk ', 'Dcmn' ) );
456 inObject['events'].push( new EventData( strOpenDocument, 'Opn ' ) );
457 inObject['events'].push( new EventData( strStartSaveDocument, 'save', 'saveBegin' ) );
458 inObject['events'].push( new EventData( strSaveDocument, 'save', 'saveSucceeded' ) );
459 inObject['events'].push( new EventData( strCloseDocument, 'Cls ' ) );
460 inObject['events'].push( new EventData( strPrintDocument, 'Prnt' ) );
461 inObject['events'].push( new EventData( strExportDocument, 'Expr' ) );
462 inObject['events'].push( new EventData( strAll, 'All ' ) );
463
464/*
465// Class IDs related to event make (new)
466 inObject['events'].push( new EventData( 'New Layer', 'Mk ', 'Lyr ' ) );
467 inObject['events'].push( new EventData( 'New Channel', 'Mk ', 'Chnl' ) );
468 inObject['events'].push( new EventData( 'New Path', 'Mk ', 'Path' ) );
469 inObject['events'].push( new EventData( 'New Text Layer', 'Mk ', 'TxLr' ) );
470 inObject['events'].push( new EventData( 'New Solid Color Layer', 'Mk ', 'solidColorLayer' ) );
471 inObject['events'].push( new EventData( 'New Gradient Layer', 'Mk ', 'gradientLayer' ) );
472 inObject['events'].push( new EventData( 'New Pattern Layer', 'Mk ', 'patternLayer' ) );
473 inObject['events'].push( new EventData( 'New Levels Layer', 'Mk ', 'Lvls' ) );
474 inObject['events'].push( new EventData( 'New Curves Layer', 'Mk ', 'Crvs' ) );
475 inObject['events'].push( new EventData( 'New Color Balance Layer', 'Mk ', 'ClrB' ) );
476 inObject['events'].push( new EventData( 'New Brightness Contrast Layer', 'Mk ', 'BrgC' ) );
477 inObject['events'].push( new EventData( 'New Hue Saturation Layer', 'Mk ', 'HStr' ) );
478 inObject['events'].push( new EventData( 'New Selective Color Layer', 'Mk ', 'SlcC' ) );
479 inObject['events'].push( new EventData( 'New Channel Mixer Layer', 'Mk ', 'ChnM' ) );
480 inObject['events'].push( new EventData( 'New Gradient Map Layer', 'Mk ', 'GdMp' ) );
481 inObject['events'].push( new EventData( 'New Photo Filter Layer', 'Mk ', 'photoFilter' ) );
482 inObject['events'].push( new EventData( 'New Invert Layer', 'Mk ', 'Invr' ) );
483 inObject['events'].push( new EventData( 'New Threshold Layer', 'Mk ', 'Thrs' ) );
484 inObject['events'].push( new EventData( 'New Posterize Layer', 'Mk ', 'Pstr' ) );
485 inObject['events'].push( new EventData( 'New Brush', 'Mk ', 'Brsh' ) );
486 inObject['events'].push( new EventData( 'New Snapshot', 'Mk ', 'SnpS' ) );
487 inObject['events'].push( new EventData( 'New Swatch', 'Mk ', 'Clrs' ) );
488 inObject['events'].push( new EventData( 'New Tool Preset', 'Mk ', 'toolPreset' ) );
489 inObject['events'].push( new EventData( 'New Guide', 'Mk ', 'Gd ' ) );
490 inObject['events'].push( new EventData( 'New Spot Color Channel', 'Mk ', 'SCch' ) );
491 inObject['events'].push( new EventData( 'New Group from Layers', 'Mk ', 'layerSection' ) );
492 inObject['events'].push( new EventData( 'New Comp', 'Mk ', 'compsClass' ) );
493
494 // generic make, this will get all makes
495 inObject['events'].push( new EventData( 'New Anything', 'Mk ' ) );
496*/
497
498/*
499// Class IDs related to event select
500 inObject['events'].push( new EventData( 'Select Layer', 'slct', 'Lyr ' ) );
501 inObject['events'].push( new EventData( 'Select Channel', 'slct', 'Chnl' ) );
502 inObject['events'].push( new EventData( 'Select Document', 'slct', 'Dcmn' ) );
503 inObject['events'].push( new EventData( 'Select Path', 'slct', 'Path' ) );
504
505 // generic select, this will get all selects
506 inObject['events'].push( new EventData( 'Select Anything', 'slct' ) );
507*/
508
509/*
510// Class IDs related to event delete
511 inObject['events'].push( new EventData( 'Delete Layer', 'Dlt ', 'Lyr ' ) );
512 inObject['events'].push( new EventData( 'Delete Channel', 'Dlt ', 'Chnl' ) );
513 inObject['events'].push( new EventData( 'Delete Path', 'Dlt ', 'Path' ) );
514
515 // generic delete, this will get all deletes
516 inObject['events'].push( new EventData( 'Delete Anything', 'Dlt ' ) );
517*/
518
519}
520
521
522///////////////////////////////////////////////////////////////////////////////
523// Function: GlobalVariables
524// Usage: global action items that are reused
525// Input: <none>
526// Return: <none>
527///////////////////////////////////////////////////////////////////////////////
528function GlobalVariables() {
529 gClassActionSet = charIDToTypeID( 'ASet' );
530 gClassAction = charIDToTypeID( 'Actn' );
531 gKeyName = charIDToTypeID( 'Nm ' );
532 gKeyNumberOfChildren = charIDToTypeID( 'NmbC' );
533}
534
535
536///////////////////////////////////////////////////////////////////////////////
537// Function: GlobalStrings
538// Usage: add your strings here that should be localized via the Photoshop
539// zstring table, all items here are global scope
540// Input: <none>
541// Return: <none>
542///////////////////////////////////////////////////////////////////////////////
543function GlobalStrings() {
544 strTitle = localize( '$$$/JavaScript/ScriptEventsManager/Title=Script Events Manager' );
545 strAdd = localize( '$$$/JavaScript/ScriptEventsManager/Add=&Add' );
546 strEvent = localize( '$$$/JavaScript/ScriptEventsManager/Event=Photoshop Event:' );
547 strScript = localize( '$$$/JavaScript/ScriptEventsManager/Script=&Script:' );
548 strOK = localize( '$$$/JavaScript/ScriptEventsManager/OK=OK' );
549 strDone = localize( '$$$/JavaScript/ScriptEventsManager/Done=&Done' );
550 strCancel = localize( '$$$/JavaScript/ScriptEventsManager/Cancel=Cancel' );
551 strRemove = localize( '$$$/JavaScript/ScriptEventsManager/Remove=&Remove' );
552 strRemoveAll = localize( '$$$/JavaScript/ScriptEventsManager/RemoveAll=Remo&ve All' );
553 strAction = localize( '$$$/JavaScript/ScriptEventsManager/Action=Action' );
554 strActionDialog = localize( '$$$/JavaScript/ScriptEventsManager/ActionDialog=A&ction' );
555 strScriptEventsFolder = localize( '$$$/JavaScript/ScriptEventsManager/Folder=/Presets/Scripts/Event Scripts Only/' );
556 strName = localize( '$$$/JavaScript/ScriptEventsManager/Name=Event Name:' );
557 strValue = localize( '$$$/JavaScript/ScriptEventsManager/Value=Descriptive Label:' );
558 strPleaseSelect = localize( '$$$/JavaScript/ScriptEventsManager/PleaseSelect=Please select an installed notifier to remove.' );
559 strActionNotifier = localize( '$$$/JavaScript/ScriptEventsManager/ActionNotifier=ActionNotifier' );
560 strBrowse = localize( '$$$/JavaScript/ScriptEventsManager/Browse=Browse' );
561 strAddEvent = localize( '$$$/JavaScript/ScriptEventsManager/AddEvent=Add an Event' );
562 strFileExtension = localize( '$$$/JavaScript/ScriptEventsManager/FileExtension=JavaScript Files: *.js*' );
563 strSelectFile = localize( '$$$/JavaScript/ScriptEventsManager/SelectFile=Select a JavaScript file' );
564 strBigError = localize( "$$$/JavaScript/ScriptEventsManager/BigError=Sorry, something major happened and I can't continue! Would you like to see more info?" );
565 strStartApplication = localize( '$$$/JavaScript/ScriptEventsManager/StartApplication=Start Application' );
566 strNewDocument = localize( '$$$/JavaScript/ScriptEventsManager/NewDocument=New Document' );
567 strOpenDocument = localize( '$$$/JavaScript/ScriptEventsManager/OpenDocument=Open Document' );
568 strStartSaveDocument = localize( '$$$/JavaScript/ScriptEventsManager/StartSaveDocument=Start Save Document' );
569 strSaveDocument = localize( '$$$/JavaScript/ScriptEventsManager/SaveDocument=Save Document' );
570 strCloseDocument = localize( '$$$/JavaScript/ScriptEventsManager/CloseDocument=Close Document' );
571 strPrintDocument = localize( '$$$/JavaScript/ScriptEventsManager/PrintDocument=Print Document' );
572 strExportDocument = localize( '$$$/JavaScript/ScriptEventsManager/ExportDocument=Export Document' );
573 strAll = localize( '$$$/JavaScript/ScriptEventsManager/All=Everything' );
574 strEventHelp = localize( '$$$/JavaScript/ScriptEventsManager/EventHelp=Select an event' );
575 strFileHelp = localize( '$$$/JavaScript/ScriptEventsManager/FileHelp=Select a JavaScript file' );
576 strActionHelp = localize( '$$$/JavaScript/ScriptEventsManager/ActionHelp=Select an action set and an action' );
577 strAddHelp = localize( '$$$/JavaScript/ScriptEventsManager/AddHelp=Click to add the event' );
578 strEventsHelp = localize( '$$$/JavaScript/ScriptEventsManager/EventsHelp=List of events currently enabled' );
579 strRemoveHelp = localize( '$$$/JavaScript/ScriptEventsManager/RemoveHelp=Click to remove the selected event' );
580 strRemovAllHelp = localize( '$$$/JavaScript/ScriptEventsManager/RemoveAllHelp=Click to remove all the events' );
581 strDescription = localize( '$$$/JavaScript/ScriptEventsManager/Description=Description' );
582 strDescriptionText = localize( '$$$/JavaScript/ScriptEventsManager/DescriptionText=Manage your events by adding and removing. Select different JavaScript files to get detailed descriptions.' );
583 strAddFilesError = localize( '$$$/JavaScript/ScriptEventsManager/AddFilesError=Use the Browse item to add JavaScript files to the list.' );
584 strEnterAValue = localize( '$$$/JavaScript/ScriptEventsManager/EnterAValue=Please enter a descriptive label.' );
585 strEnterAName = localize( '$$$/JavaScript/ScriptEventsManager/EnterAName=Please enter an event name.' );
586 strNotifierAlreadyInstalled = localize( '$$$/ScriptingSupport/Error/NotifierAlreadyInstalled=Notifier already installed' );
587 strError = localize( '$$$/JavaScript/ScriptEventsManager/Error=Error: ' );
588 strEnabled = localize( '$$$/JavaScript/ScriptEventsManager/Enabled=&Enable Events to Run Scripts/Actions:' );
589 strEnabledHelp = localize( '$$$/JavaScript/ScriptEventsManager/EnabledHelp=Enable or disable all notifiers' );
590 strCannotOpen = localize( '$$$/JavaScript/ScriptEventsManager/CannotOpen=Cannot open file to save ' );
591 strCannotWrite = localize( '$$$/JavaScript/ScriptEventsManager/CannotWrite=Cannot write to file ' );
592 strCannotUndefined = localize( '$$$/JavaScript/ScriptEventsManager/CannotUndefined=Cannot save, file name is undefined.' );
593 strNoScripts = localize( '$$$/JavaScript/ScriptEventsManager/NoScripts=no scripts/actions associated with events' );
594 strSeeDocs = localize( '$$$/JavaScript/ScriptEventsManager/SeeDocs=Any scriptable event can be entered here. See the Scripting Reference for the full list of Photoshop event names.' );
595 strPickAnExistingFile = localize( '$$$/JavaScript/ScriptEventsManager/PickAnExistingFile=Please select an existing file.' );
596 strPickAFileWithAJavaScriptExtension = localize( '$$$/JavaScript/ScriptEventsManager/PickAFileWithJavaScriptExtension=Please select a file with a JavaScript extension. ( js or jsx)' );
597 strlbEventsHeight = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/LBEventsHeight=126" );
598 strlbEventsWidth = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/LBEventsWidth=400" );
599 strstDescription = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/STDescription=65" );
600 stretName = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/ETName=200" );
601 stretValue = localize( "$$$/locale_specific/JavaScripts/ScriptEventsManager/ETValue=200" );
602}
603
604
605///////////////////////////////////////////////////////////////////////////////
606// Function: UpdateRemovePanel
607// Usage: update the list box for all the installed notifiers
608// Input: list box, remove button and remove all button
609// Return: <none>
610// Note: This list box is sorted by the following rules.
611// 1. Events are shown in the same order as the Event listbox
612// 2. In alphabetical order for > 1 script/action per event
613///////////////////////////////////////////////////////////////////////////////
614function UpdateRemovePanel( lb, btn, btnAll ) {
615 if ( app.notifiers.length > 0 ) {
616 lb.removeAll();
617 var allEvents = new Array( app.notifiers.length );
618 for ( var i = 0; i < app.notifiers.length; i++ ) {
619 var niceName = app.notifiers[i].event;
620 for ( var b = 0; b < gEvents.length; b++ ) {
621 if ( gEvents[b].value == app.notifiers[i].event &&
622 gEvents[b].valueClass == app.notifiers[i].eventClass ) {
623 niceName = gEvents[b].name;
624 break;
625 }
626 }
627 var betterDescription = File.decode( app.notifiers[i].eventFile.name.toString() );
628 if ( true == app.notifiers[i].eventFile.alias ) {
629 betterDescription = File.decode( app.notifiers[i].eventFile.resolve().name.toString() );
630 }
631 var inFile = app.notifiers[i].eventFile;
632 inFile.open( "r" );
633 var firstLine = inFile.readln();
634 var splitUp = firstLine.split( ", " );
635 if ( 4 == splitUp.length && splitUp[ 0 ] == gUniqueID ) {
636 betterDescription = splitUp[ 3 ] + " " + strAction + " (" + splitUp[ 2 ] + ")";
637 }
638 inFile.close();
639 allEvents[ i ] = niceName + ": " + betterDescription;
640 }
641 allEvents.sort( EventSort );
642 for ( var i = 0; i < allEvents.length; i++ ) {
643 lbEvents.add( "item", allEvents[ i ] );
644 }
645 // this used to select the new item in the list
646 // now I have sorted them, how do I find the new one?
647 // i could remember the old list and mark each one at a time
648 // what about on start up?
649 lb.items[ lb.items.length - 1 ].selected = true;
650 btn.enabled = true;
651 btnAll.enabled = true;
652 } else {
653 UpdateForNoNotifiers();
654 }
655}
656
657
658///////////////////////////////////////////////////////////////////////////////
659// Function: UpdateEventDropDown
660// Usage: Populate the drop down list with the events or add an event
661// Input: drop down list to update, new event created
662// Return: the index of the custom event menu item
663///////////////////////////////////////////////////////////////////////////////
664function UpdateEventDropDown( dd, newEvent ) {
665 var customIndex = 0;
666 if ( undefined == newEvent ) {
667 dd.removeAll();
668 for ( var i = 0; i < gEvents.length; i++ ) {
669 dd.add( "item", gEvents[i].name );
670 }
671 customIndex = dd.items.length + 1;
672 dd.add( "separator", "before custom" );
673 dd.add( "item", strAddEvent + "..." );
674
675 dd.items[0].selected = true;
676 } else {
677 customIndex = gCustomEventIndex;
678 if ( gCustomEventIndex == ( dd.items.length - 1 ) ) {
679 dd.add( "separator", "after custom" );
680 }
681 dd.add( "item", gEvents[ gEvents.length - 1 ].name );
682 dd.items[ dd.items.length - 1 ].selected = true;
683 }
684 return customIndex;
685}
686
687
688///////////////////////////////////////////////////////////////////////////////
689// Function: CreateNewEvent
690// Usage: pop another dialog to create a new event
691// Input: <none>
692// Return: a new EventData object
693///////////////////////////////////////////////////////////////////////////////
694function CreateNewEvent() {
695 var newEvent;
696 var dlgNewEvent = new Window( 'dialog' );
697
698 dlgNewEvent.text = strAddEvent;
699 dlgNewEvent.orientation = 'row';
700 dlgNewEvent.alignChildren = 'top';
701 var grpLeft = dlgNewEvent.add( 'group' );
702 grpLeft.orientation = 'column';
703 grpLeft.alignChildren = 'right';
704 var grpName = grpLeft.add( 'group' );
705 grpName.orientation = 'row';
706 var stName = grpName.add( 'statictext' );
707 stName.text = strName;
708 var etName = grpName.add( 'edittext' );
709 etName.preferredSize.width = StrToIntWithDefault( stretName, 200 );
710 var grpValue = grpLeft.add( 'group' );
711 grpValue.orientation = 'row';
712 var stValue = grpValue.add( 'statictext' );
713 stValue.text = strValue;
714 var etValue = grpValue.add( 'edittext' );
715 etValue.preferredSize.width = StrToIntWithDefault( stretValue, 200 );
716 var grpMessage = grpLeft.add( 'group' );
717 grpMessage.orientation = 'row';
718 var pngI = grpMessage.add( "image", undefined, 'InfoIcon' );
719 var stDescription = grpMessage.add( 'statictext', undefined, undefined, {multiline:true} );
720 stDescription.text = strSeeDocs;
721 var pnlRight = dlgNewEvent.add( 'group' );
722 pnlRight.orientation = 'column';
723 pnlRight.alignChildren = 'fill';
724 var btnOk = pnlRight.add( 'button', undefined, strOK );
725 var btnCancel = pnlRight.add( 'button', undefined, strCancel );
726
727 dlgNewEvent.defaultElement = btnOk;
728 dlgNewEvent.cancelElement = btnCancel;
729
730 dlgNewEvent.center();
731
732 btnOk.onClick = function() {
733 if ( 0 == etName.text.length ) {
734 alert( strEnterAName );
735 return;
736 }
737 if ( 0 == etValue.text.length ) {
738 alert( strEnterAValue );
739 return;
740 }
741 dlgNewEvent.close( true );
742 }
743
744 if ( true == dlgNewEvent.show() ) {
745 var splitValue = etValue.text.split( "," );
746 newEvent = new EventData( etName.text, splitValue[0], splitValue[1] );
747 }
748
749 return newEvent;
750}
751
752
753///////////////////////////////////////////////////////////////////////////////
754// Function: UpdateScriptsFileDropDown
755// Usage: Update the scripts drop down list, on init of the dialog I pull the
756// data from the presets/scripts/event scripts only folder
757// if the user browses to a new file then add it and some separators
758// Input: the drop down list to update, the file from the browse
759// Return: the index of the browse menu item
760///////////////////////////////////////////////////////////////////////////////
761function UpdateScriptsFileDropDown( dd, newFile ) {
762 var customIndex = 0;
763 if ( undefined == newFile ) {
764 var allFiles = Folder( path + strScriptEventsFolder ).getFiles();
765 gScriptsFiles = new Array();
766 if ( allFiles.length > 0 ) {
767 dd.removeAll();
768 for ( var i = 0; i < allFiles.length; i++ ) {
769 if ( allFiles[i].name.substr( 0, strActionNotifier.length ) != strActionNotifier &&
770 IsJavaScriptExtension( allFiles[i] ) ) {
771
772 var dataForMenu = GetDescriptionAndMenuNameFromFile( allFiles[i] );
773 var menuItem = dd.add( "item", dataForMenu["Name"] );
774 menuItem.description = dataForMenu["Desc"];
775 gScriptsFiles.push( allFiles[i] );
776
777 }
778 }
779 }
780 if ( undefined != gExtraFiles ) {
781 for ( var i = 0; i < gExtraFiles.length; i++ ) {
782 var dataForMenu = GetDescriptionAndMenuNameFromFile( File( gExtraFiles[i] ) );
783 var menuItem = dd.add( "item", dataForMenu["Name"] );
784 menuItem.description = dataForMenu["Desc"];
785 gScriptsFiles.push( File( gExtraFiles[i] ) );
786 }
787 }
788 if ( dd.items.length > 0 ) {
789 dd.items[0].selected = true;
790 }
791 customIndex = dd.items.length + 1;
792 dd.add( "separator", "before custom" );
793 dd.add( "item", strBrowse + "..." );
794 } else {
795 customIndex = gCustomFileIndex;
796 if ( gCustomFileIndex == ( dd.items.length - 1 ) ) {
797 dd.add( "separator", "after custom" );
798 }
799 var dataForMenu = GetDescriptionAndMenuNameFromFile( newFile );
800 var menuItem = dd.add( "item", dataForMenu["Name"] );
801 menuItem.description = dataForMenu["Desc"];
802 dd.items[ dd.items.length - 1 ].selected = true;
803 gScriptsFiles.push( newFile );
804 if ( undefined == gExtraFiles ) {
805 gExtraFiles = new Array();
806 gParams.Set( 'extrafiles', gExtraFiles );
807 }
808 gExtraFiles.push( newFile.absoluteURI );
809 }
810 return customIndex;
811}
812
813
814///////////////////////////////////////////////////////////////////////////////
815// Function: AddFileNotifier
816// Usage: The add button was clicked, add the notifier from the drop downs
817// Input: two drop down lists, event and file
818// Return: <none>
819// Note: I have to adjust for the custom items and the separators
820///////////////////////////////////////////////////////////////////////////////
821function AddFileNotifier( edd, fdd ) {
822 try {
823 if ( null == fdd.selection && 0 == gScriptsFiles.length ) {
824 throw strAddFilesError;
825 }
826 var eventsIndex = edd.selection.index;
827 if ( eventsIndex > gCustomEventIndex ) {
828 eventsIndex -= 3;
829 }
830 var filesIndex = fdd.selection.index;
831 if ( filesIndex > gCustomFileIndex ) {
832 filesIndex -= 3;
833 }
834 app.notifiers.add( gEvents[ eventsIndex ].value, gScriptsFiles[ filesIndex ], gEvents[ eventsIndex ].valueClass );
835 }
836 catch( e ) {
837 alert( e );
838 }
839}
840
841
842///////////////////////////////////////////////////////////////////////////////
843// Function: AddActionNotifier
844// Usage: Create a JavaScript file with the code to execute an action from
845// an action set
846// Input: three drop down lists, event, action set and action, and the events list box
847// Return: <none>
848///////////////////////////////////////////////////////////////////////////////
849function AddActionNotifier( edd, sdd, add, lb ) {
850 try {
851 var strLookingFor = edd.selection.toString() + ": " + add.selection.toString() + " " + strAction + " (" + sdd.selection.toString() + ")";
852 for ( var i = 0; i < lb.items.length; i++ ) {
853 if ( lb.items[i].toString() == strLookingFor ) {
854 throw ( strError + strNotifierAlreadyInstalled );
855 }
856 }
857 var uniqueFileName = CreateUniqueFileName( app.preferencesFolder.toString() + "/", strActionNotifier, ".jsx" );
858 var outFile = new File ( uniqueFileName );
859 var addStr = escape( add.selection.toString() );
860 addStr = encodeURI( addStr );
861 var sddStr = escape( sdd.selection.toString() );
862 sddStr = encodeURI( sddStr );
863 outFile.open( "w" );
864 outFile.writeln( gUniqueID + ", " + edd.selection.toString() + ", " + sdd.selection.toString() + ", " + add.selection.toString() );
865 outFile.writeln( "try {" );
866 outFile.writeln( " var actionStr = '" + addStr.toString() + "';" );
867 outFile.writeln( " actionStr = decodeURI( actionStr );" );
868 outFile.writeln( " actionStr = unescape( actionStr );" );
869 outFile.writeln( " var actionSetStr = '" + sddStr.toString() + "';" );
870 outFile.writeln( " actionSetStr = decodeURI( actionSetStr );" );
871 outFile.writeln( " actionSetStr = unescape( actionSetStr );" );
872 outFile.writeln( " doAction( actionStr, actionSetStr );" );
873 outFile.writeln( "}" );
874 outFile.writeln( "catch( e ) { }" );
875 outFile.close();
876 var eventsIndex = edd.selection.index;
877 if ( eventsIndex > gCustomEventIndex ) {
878 eventsIndex -= 3;
879 }
880 app.notifiers.add( gEvents[ eventsIndex ].value, outFile, gEvents[ eventsIndex ].valueClass );
881 }
882 catch( e ) {
883 alert( e );
884 }
885}
886
887
888///////////////////////////////////////////////////////////////////////////////
889// Function: CreateUniqueFileName
890// Usage: given a folder, file name and extenstion create a file with a unique
891// file name
892// Input: given a folder, file name and extenstion
893// Return: the full path to the unique file
894///////////////////////////////////////////////////////////////////////////////
895function CreateUniqueFileName( inFolder, inFileName, inExtension ) {
896 var uniqueFileName = inFolder + inFileName + inExtension;
897 var fileNumber = 1;
898 while ( File( uniqueFileName ).exists ) {
899 uniqueFileName = inFolder + inFileName + "_" + fileNumber + inExtension;
900 fileNumber++;
901 }
902 return uniqueFileName;
903}
904
905
906///////////////////////////////////////////////////////////////////////////////
907// Function: MacJSFilter
908// Input: f, file or folder to check
909// Return: true or false, true if file or folder is to be displayed
910///////////////////////////////////////////////////////////////////////////////
911function MacJSFilter( f )
912{
913 var jsExtension = ".js";
914 var jsExtension2 = ".jsx";
915 var folderThatsAnApp = ".app"; // this doesn't cover all packages or bundles
916 var lCaseName = f.name;
917 lCaseName.toLowerCase();
918 if ( lCaseName.lastIndexOf( jsExtension ) == f.name.length - jsExtension.length )
919 return true;
920 else if ( lCaseName.lastIndexOf( jsExtension2 ) == f.name.length - jsExtension2.length )
921 return true;
922 else if ( lCaseName.lastIndexOf( folderThatsAnApp ) == f.name.length - folderThatsAnApp.length )
923 return false;
924 else if ( f instanceof Folder )
925 return true;
926 else
927 return false;
928}
929
930
931///////////////////////////////////////////////////////////////////////////////
932// Function: GetDescriptionAndMenuNameFromFile
933// Usage: Return the descriptive text and the name for the menu dropdown from
934// variables in the file. The default description "Desc" is strDescriptionText
935// and the default menu "Name" is the file name.
936// The description should be stored so this only gets called once per file.
937// Input: file to read out a description, not an alias
938// Output: Array of "Desc" and "Name" for each file
939///////////////////////////////////////////////////////////////////////////////
940function GetDescriptionAndMenuNameFromFile( inFile ) {
941 var result = new Array;
942 result["Desc"] = strDescriptionText;
943 var readFile = inFile;
944 if ( true == inFile.alias ) {
945 readFile = inFile.resolve();
946 }
947 result["Name"] = File.decode( readFile.name );
948 var searchStrings = [ "Desc", "Name" ];
949 if ( undefined != readFile ) {
950 if ( readFile.open( "r" ) ) {
951 var readLength = 1000;
952 if ( readFile.length < readLength ) {
953 readLength = readFile.length;
954 }
955 var readData = readFile.read( readLength );
956 readFile.close();
957 for ( var i = 0; i < searchStrings.length; i++ ) {
958 var stringStartNew = 'var beg' + searchStrings[i] + ' = "';
959 var stringEndNew = '" // end' + searchStrings[i];
960 var descriptionStart = readData.indexOf( stringStartNew, 0 ) + stringStartNew.length;
961 var descriptionEnd = readData.indexOf( stringEndNew, descriptionStart );
962 if ( descriptionStart != -1 && descriptionEnd != -1 && descriptionEnd > descriptionStart ) {
963 result[ searchStrings[i] ] = localize( readData.substr( descriptionStart, descriptionEnd - descriptionStart ) );
964 }
965 // really old backwards compatibility search
966 if ( result["Desc"] == strDescriptionText && searchStrings[i] == "Desc" ) {
967 var stringStartOld = '/** "';
968 var stringEndOld = '" **/';
969 var descriptionStart = readData.indexOf( stringStartOld, 0 ) + stringStartOld.length;
970 var descriptionEnd = readData.indexOf( stringEndOld, descriptionStart );
971 if ( descriptionStart != -1 && descriptionEnd != -1 && descriptionEnd > descriptionStart ) {
972 result[ searchStrings[i] ] = localize( readData.substr( descriptionStart, descriptionEnd - descriptionStart ) );
973 }
974 }
975 }
976 }
977 }
978 return result;
979}
980
981
982///////////////////////////////////////////////////////////////////////////////
983// Function: IsJavaScriptExtension
984// Usage: See if the file extension is .js or .jsx
985// Input: file to check extension
986// Output: true if extension is .js or .jsx, false otherwise
987///////////////////////////////////////////////////////////////////////////////
988function IsJavaScriptExtension( inFile ) {
989 var returnValue = false;
990 var realFileName = inFile.name;
991 if ( true == inFile.alias ) {
992 realFileName = inFile.resolve().name;
993 }
994 var splitFileName = realFileName.split( "." );
995 if ( splitFileName.length > 1 ) {
996 var lastDot = splitFileName.length - 1;
997 splitFileName[ lastDot ] = splitFileName[ lastDot ].toLowerCase();
998 if ( splitFileName[ lastDot ] == "js" || splitFileName[ lastDot ] == "jsx" ) {
999 returnValue = true;
1000 }
1001 }
1002 return returnValue;
1003}
1004
1005
1006///////////////////////////////////////////////////////////////////////////////
1007// Function: GetScriptNameForXML
1008// Usage: You can't save certain characters in xml, strip them here
1009// NOTE: This list is not complete
1010// Input: <none>
1011// Output: The title stripped of characters bad for xml
1012///////////////////////////////////////////////////////////////////////////////
1013function GetScriptNameForXML () {
1014 var scriptNameForXML = new String( strTitle );
1015 var charsToStrip = Array( " ", "'", "." );
1016 for (var a = 0; a < charsToStrip.length; a++ ) {
1017 var nameArray = scriptNameForXML.split( charsToStrip[a] );
1018 scriptNameForXML = "";
1019 for ( var b = 0; b < nameArray.length; b++ ) {
1020 scriptNameForXML += nameArray[b];
1021 }
1022 }
1023 return scriptNameForXML;
1024}
1025
1026
1027///////////////////////////////////////////////////////////////////////////////
1028// Function: GetDefaultParamsFile
1029// Usage: Get the file where I store my default parameters
1030// Input: <none>, global strTitle must be defined
1031// Output: Location of File of my parameters
1032///////////////////////////////////////////////////////////////////////////////
1033function GetDefaultParamsFile() {
1034 return ( new File( app.preferencesFolder + "/" + strTitle + ".xml" ) );
1035}
1036
1037
1038///////////////////////////////////////////////////////////////////////////////
1039// Function: Parameters
1040// Usage: Object to load and save parameters to disk
1041// Input: inFileName is the path to the file, initRoutine will be called
1042// to create your default parameters
1043// Output: new object, use the Get(), Set(), Load() and Save() routines
1044// other routines are for private use by the object
1045///////////////////////////////////////////////////////////////////////////////
1046function Parameters( inFileName, initRoutine ) {
1047
1048 // functions for public use
1049
1050 this.Get = function ( index ) {
1051 return this.data[index];
1052 }
1053
1054 this.Set = function ( index, value ) {
1055 this.data[index] = value;
1056 }
1057
1058 this.Load = function ( ) {
1059 if ( File( this.fileName ).exists ) {
1060 var loadFile = File( this.fileName );
1061 if ( loadFile.open( "r" ) ) {
1062 var strXML = loadFile.read( loadFile.length );
1063 loadFile.close();
1064 var startSpace = strXML.indexOf( "<" ) + 1;
1065 var endSpace = strXML.indexOf( ">" );
1066 if ( endSpace == -1 ) return;
1067 var projectSpace = strXML.substring( startSpace, endSpace );
1068 if ( projectSpace == GetScriptNameForXML() ) {
1069 strXML = strXML.substring( endSpace + 1, strXML.length );
1070 this.ReadElements( strXML, this.data );
1071 }
1072 }
1073 }
1074 }
1075
1076 this.Save = function ( ) {
1077 if ( undefined == this.fileName ) {
1078 alert( strCannotUndefined );
1079 return;
1080 }
1081 var saveFile = File( this.fileName );
1082 saveFile.encoding = "UTF8";
1083 if ( saveFile.open( "w", "TEXT", "????" ) ) {
1084 if ( saveFile.write( "\uFEFF" ) ) {
1085 saveFile.writeln( "<" + GetScriptNameForXML() + ">" );
1086 this.WriteData( saveFile, this.data );
1087 saveFile.writeln( "</" + GetScriptNameForXML() + ">" );
1088 saveFile.close();
1089 } else {
1090 alert( strCannotWrite + this.fileName.fsName );
1091 saveFile.close();
1092 return;
1093 }
1094 } else {
1095 alert( strCannotOpen + this.fileName.fsName );
1096 }
1097 }
1098
1099 // functions for private use
1100
1101 this.Initialize = function( initRoutine ) {
1102 if ( undefined != initRoutine ) {
1103 initRoutine( this.data );
1104 }
1105 }
1106
1107 this.WriteData = function( inFile, inData ) {
1108 this.tabLevel++;
1109 var prop;
1110 for ( prop in inData ) {
1111 if ( typeof( inData[ prop ] ) == "object" ) {
1112 this.WriteTabs( inFile, this.tabLevel );
1113 inFile.writeln( "<" + prop + ">" );
1114 this.WriteData( inFile, inData[ prop ] );
1115 this.WriteTabs( inFile, this.tabLevel );
1116 inFile.writeln( "</" + prop + ">" );
1117 } else {
1118 this.WriteTabs( inFile, this.tabLevel );
1119 inFile.writeln( "<" + prop + ">" + inData[ prop ] + "</" + prop + ">" );
1120 }
1121 }
1122 this.tabLevel--;
1123 }
1124
1125 this.WriteTabs = function( inFile, tabs ) {
1126 while ( tabs-- ) {
1127 inFile.write( "\t" );
1128 }
1129 }
1130
1131 this.ReadElements = function( inText, inData ) {
1132 while ( inText.length ) {
1133 var startMarker = inText.indexOf( "<" ) + 1;
1134 var endMarker = inText.indexOf( ">" );
1135 if ( endMarker == -1 ) break;
1136 var starter = inText.substring( startMarker, endMarker );
1137 var enderIndex = inText.indexOf( "</" + starter + ">" );
1138 if ( enderIndex == -1 ) break;
1139 var data = inText.substring( endMarker + 1, enderIndex );
1140 if ( data.search( "<" ) != -1 ) {
1141 inData[ starter ] = new Array();
1142 this.ReadElements( data, inData[ starter ] );
1143 } else {
1144 inData[ starter ] = data;
1145 }
1146 // force boolean values to boolean types
1147 if ( data == "true" || data == "false" ) {
1148 inData[ starter ] = data == "true";
1149 }
1150 // should I force number values to numbers ???
1151 inText = inText.substring( enderIndex + ("</" + starter + ">" ).length, inText.length );
1152 }
1153 }
1154
1155 // internal variables, public should not access
1156
1157 this.fileName = inFileName;
1158
1159 this.data = new Array();
1160
1161 this.tabLevel = 0;
1162
1163 this.Initialize( initRoutine );
1164}
1165
1166
1167///////////////////////////////////////////////////////////////////////////////
1168// Function: UpdateForNoNotifiers
1169// Usage: set up the events list box for no events and disable the buttons
1170// Input: <none> : globals btnRemove, btnRemoveAll, strNoScripts and lbEvents
1171// Return: <none>
1172///////////////////////////////////////////////////////////////////////////////
1173function UpdateForNoNotifiers() {
1174 btnRemove.enabled = false;
1175 btnRemoveAll.enabled = false;
1176 lbEvents.add( "item", strNoScripts );
1177}
1178
1179
1180///////////////////////////////////////////////////////////////////////////////
1181// Function: EventSort
1182// Usage: sort function for the events list box
1183// Input: a, b are the two events to sort
1184// Return: -1 or 1, no need for 0 as there should be no dupes
1185///////////////////////////////////////////////////////////////////////////////
1186function EventSort( a, b ) {
1187 var aa = a.split( ":" );
1188 if ( aa.length < 2 ) {
1189 return -1;
1190 }
1191 var bb = b.split( ":" );
1192 if ( bb.length < 2 ) {
1193 return 1;
1194 }
1195 var aaIndex = 0;
1196 var bbIndex = 0;
1197 for ( var i = 0; i < ddEvent.items.length; i++ ) {
1198 if ( ddEvent.items[ i ].toString() == aa[ 0 ] ) {
1199 aaIndex = i;
1200 }
1201 if ( ddEvent.items[ i ].toString() == bb[ 0 ] ) {
1202 bbIndex = i;
1203 }
1204 }
1205 if ( bbIndex == aaIndex ) {
1206 var cc = [ aa[ 1 ], bb[ 1 ] ];
1207 cc.sort();
1208 if ( cc[ 0 ] == aa[ 1 ] ) {
1209 return -1;
1210 } else {
1211 return 1;
1212 }
1213 } else {
1214 if ( aaIndex < bbIndex ) {
1215 return -1;
1216 } else {
1217 return 1;
1218 }
1219 }
1220 return -1;
1221}
1222
1223///////////////////////////////////////////////////////////////////////////
1224// Function: StrToIntWithDefault
1225// Usage: convert a string to a number, first stripping all characters
1226// Input: string and a default number
1227// Return: a number
1228///////////////////////////////////////////////////////////////////////////
1229function StrToIntWithDefault( s, n ) {
1230 var onlyNumbers = /[^0-9]/g;
1231 var t = s.replace( onlyNumbers, "" );
1232 t = parseInt( t );
1233 if ( ! isNaN( t ) ) {
1234 n = t;
1235 }
1236 return n;
1237}
1238// end Script Events Manager.jsx