Forenindex » Programme » Print/Bildbearbeitung » Adobe InDesign Skriptwerkstatt » Interaktives Panel

Interaktives Panel

tsone
Beiträge gesamt: 70

10. Jul 2017, 17:45
Bewertung:

gelesen: 11911

Beitrag als Lesezeichen
Hallo Leute,

ich habe in InDesign ein eigenes Panel laufen, bei dem ich mit Buttons verschiedene JSX ausführen kann, die sich auf das geöffnete InDesign-Dokument auswirken.

Jetzt möchte ich aber, dass in dem Panel selber was passiert. Zum Beispiel, dass er mir im Panel den Namen des gerade ausgewählten Objektes anzeigt. Ich weiß, dass ich das auch über die Ebenen-Palette sehen kann - allerdings wird das unübersichtlich, wenn ich dort viele Ebenen habe, die teilweise zugeklappt sind.

Hat da jemand eine Idee?

Danke und Grüße

Interaktives Panel

drerol74
Beiträge gesamt: 507

12. Jul 2017, 00:46
Bewertung:

gelesen: 11439

Beitrag als Lesezeichen
Hallo,

um welches Panel handelt es sich denn, HTML? Bzw. welche InDesign-Version?

Schöne Grüße
Roland

Interaktives Panel

tsone
Beiträge gesamt: 70

12. Jul 2017, 08:15
Bewertung:

gelesen: 11256

Beitrag als Lesezeichen
Hallo Roland,

es handelt sich um InDesign CC 2017 also ein HTML-Panel.

Interaktives Panel

drerol74
Beiträge gesamt: 507

12. Jul 2017, 18:42
Bewertung:

gelesen: 10992

Beitrag als Lesezeichen
So sollte es gehen. Hier wrid als Beispiel nach Klick auf den Button der Constructor der aktuellen InDesign-Auswahl angezeigt:

JavaScript:

Code
(function () { 

'use strict';

var csInterface = new CSInterface();
var output = document.getElementById("constructor-name");

document.getElementById('test-button').addEventListener('click', function () {
csInterface.evalScript('__main()');
});

csInterface.addEventListener("custom_event", function(event) {
output.innerHTML = event.data;
});

}());



ExtendScript:

Code
function __main() { 

if(app.documents.length == 0) { return false; }

var _selection = app.selection;
if(!_selection) { return false; }

var _constructorName = _selection[0].constructor.name;

try {
var _externalObjLib = new ExternalObject("lib:\PlugPlugExternalObject");
} catch(_error) {
alert(_error);
}

if(!_externalObjLib) { return false; }

var _csxsEventObj = new CSXSEvent();

_csxsEventObj.type = "custom_event";
_csxsEventObj.data = _constructorName;
_csxsEventObj.dispatch();

return;
} /* END function __main */



index.html:

Code
<!doctype html> 
<html>

<head>
<meta charset="utf-8"/>
<title>Interakives Panel</title>
<link rel="stylesheet" href="css/styles.css"/>
</head>

<body>
<div id="content">
<h1 id="constructor-name">Constructor erscheint hier ...</h1>
<button id="test-button">Hier klicken</button>
</div>

<script src="js/libs/CSInterface.js"></script>
<script src="js/main.js"></script>
</body>
<html>



Die Webseite von Davide Barraca ist dazu sehr zu empfehlen, dort gibt es viele Beispiele zu ähnlichen Sachen. Und nicht zu vergessen sein Buch.

https://www.davidebarranca.com

Schöne Grüße
Roland

Interaktives Panel

tsone
Beiträge gesamt: 70

13. Jul 2017, 09:23
Bewertung:

gelesen: 10439

Beitrag als Lesezeichen
Hallo Roland,

kann ich das "JavaScript" mit in die "index.html" packen und das "ExtendScript" in eine JSX?

Meine aktuellen Scripte rufe ich so auf:

index.html
Code
<button id="btn_PNGTODESKTOP72" onClick="onClickButton('PNGTODESKTOP72')">72</button> 


export.jsx:
Code
$._ext_PNGTODESKTOP72={ 
run : function() {
/********** Replace below sample code with your own JSX code **********/
var Dateiname = app.activeDocument.name.split(".")[0];
var Buchstabe_klein = Dateiname.charAt(0).toLowerCase();
var Buchstabe_gross = Dateiname.charAt(0).toUpperCase();
app.pngExportPreferences.transparentBackground = true;
app.pngExportPreferences.exportResolution = 72;
app.pngExportPreferences.pngQuality = PNGQualityEnum.HIGH;
app.activeDocument.exportFile(ExportFormat.PNG_FORMAT, File(new File("~/Desktop/" + Dateiname + ".png")));
/************************************************************************/
return appName; }, };


Danke und Grüße

Interaktives Panel

tsone
Beiträge gesamt: 70

13. Jul 2017, 13:05
Bewertung:

gelesen: 10273

Beitrag als Lesezeichen
Ah, hab mit ein bisschen Basteln was hinbekommen.

Jetzt muss das auch so funktionieren, dass ich nicht extra nen Button klicken muss. Sprich - wenn ich ein Objekt auswähle, soll er im Panel den Objekt-Namen anzeigen.

Interaktives Panel

drerol74
Beiträge gesamt: 507

13. Jul 2017, 14:33
Bewertung:

gelesen: 10205

Beitrag als Lesezeichen
Antwort auf: kann ich das "JavaScript" mit in die "index.html" packen


Du kannst den js-Code auch in dei Index-Datei schreiben. Bezüglich Wartung finde ich die Verlinkung und Auslagerung in eine eigene Datei aber praktischer.


Antwort auf: und das "ExtendScript" in eine JSX?


So war es gedacht ;)


Antwort auf: Jetzt muss das auch so funktionieren, dass ich nicht extra nen Button klicken muss. Sprich - wenn ich ein Objekt auswähle, soll er im Panel den Objekt-Namen anzeigen.


Mit dem EventListener »afterSelectionChanged«, meinst du das? Der Button war nur zur Demonstration.

Schöne Grüße
Roland

Interaktives Panel

tsone
Beiträge gesamt: 70

13. Jul 2017, 14:36
Bewertung:

gelesen: 10202

Beitrag als Lesezeichen
Hab ein wenig mit afterSelectionChanged rumgespielt.

Über das Panel passiert gar nichts. Über ein externe Skriptdatei bekomme ich auch bei verschiedenen eventListener nur Fehlermeldungen, dass das Objekt nicht mehr verfügbar ist.

Interaktives Panel

Dirk Becker
Beiträge gesamt: 193

13. Jul 2017, 20:12
Bewertung:

gelesen: 9965

Beitrag als Lesezeichen
Zitat Fehlermeldungen, dass das Objekt nicht mehr verfügbar ist


Vermutlich fehlt da die targetengine Anweisung.
https://www.google.de/...ndesign+targetengine

Interaktives Panel

tsone
Beiträge gesamt: 70

14. Jul 2017, 07:18
Bewertung:

gelesen: 9546

Beitrag als Lesezeichen
Hallo Dirk,

mit
Code
#targetengine "session" 

hat es geklappt. Allerdings bekomme ich beim InDesign öffnen, dass "undefined is not an object" ist.
Vermute mal, dass das kommt, weil noch kein Objekt ausgewählt ist.

Außerdem muss ich erst Rolands Button zweimal im Panel klicken, bis auch der "afterSelectionChanged" funktioniert.

Danach

Aber vielen Dank euch für die Hilfe!!!

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

14. Jul 2017, 09:58
Bewertung:

gelesen: 9408

Beitrag als Lesezeichen
Antwort auf [ tsone ] … Allerdings bekomme ich beim InDesign öffnen, dass "undefined is not an object" ist. Vermute mal, dass das kommt, weil noch kein Objekt ausgewählt ist.


Hallo tsone,
was heißt "beim InDesign öffnen" genau?
Du startest InDesign und erwartest, dass die Arbeit mit app.selection funktioniert? Genau das ist aber nicht der Fall solange kein Dokument geöffnet ist.

Lass mal das hier als Startup-Script laufen:

Code
#targetengine uwe-test 

app.addEventListener("afterSelectionChanged", doSomething);

function doSomething(evt)
{

// THIS WILL FAIL AFTER STARTUP OF INDESIGN:
// Do nothing if nothing is selected:
if(app.selection.length == 0){return};

// OPTIONAL:
// Do nothing if text is selected:
if(app.selection[0].hasOwnProperty("baselineShift")){return};

// Final action:
alert(app.selection.length);
};


Und dann ändere das Startup-Script zu dem hier:

Code
#targetengine uwe-test 

app.addEventListener("afterSelectionChanged", doSomething);

function doSomething(evt)
{
// Do nothing if no document is open:
if(app.documents.length == 0){return};

// OPTIONAL:
// Do nothing if nothing is selected:
if(app.selection.length == 0){return};

// OPTIONAL:
// Do nothing if text is selected:
if(app.selection[0].hasOwnProperty("baselineShift")){return};

// Final action:
alert(app.selection.length);
};


Dazwischen natürlich InDesign neustarten.

[b]Warum versuche ich Textauswahlen auszublenden?
Der Listener liefert mit Textauswahlen quasi jeden "Pups". Also zum Beispiel wenn die Einfügemarke im Text bewegt wird. Oder wenn der Anwender Text tippt, dann gilt bei jeder neuen Einfügemarke: "Hallihallo! Die Auswahl hat sich geändert!" Wirklich nach jedem Zeichen! Kann nervig werden. Braucht man jetzt nicht so rigoros umsetzen wie ich das hier mache, aber man sollte darauf gefasst sein, dass jede Menge Meldungen in kurzer Zeit auf einen zukommen können.

Es wäre zu überlegen, ob Du überhaupt mit afterSelectionChanged arbeiten solltest.
Stattdessen könntest Du ein [b]IdleTask der app hinzufügen und dem einen listener für [b]IdleEvent.ON_IDLE mit einer entsprechenden Handler-Funktion mitgeben, die die Auswahl prüft und auswertet. Da könnte man sogar einen Intervall für's Nachschauen einbauen.

Doku hier:
http://jongware.mit.edu/...c_IdleTasks.html#add
http://jongware.mit.edu/...6js/pc_IdleTask.html

Schnipsel da:

Code
var newIdleTask = app.idleTasks.add 
(
{
name : "DoSomethingIfIdleEverySecond" ,
sleep : 1000
}
);

var onIdleListener = newIdleTask.addEventListener( IdleEvent.ON_IDLE , doSomeThing , false);

function doSomeThing(evt)
{
// Your functionality goes here:
if(app.documents.length == 0){return};
if(app.selection.length > 1)
{
// Notify my panel
}

};

*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

tsone
Beiträge gesamt: 70

14. Jul 2017, 10:33
Bewertung:

gelesen: 9382

Beitrag als Lesezeichen
Hallo Uwe,

das mit dem IdleTask schaue ich mir mal.

Danke und Grüße
Timo

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

14. Jul 2017, 11:16
Bewertung:

gelesen: 9352

Beitrag als Lesezeichen
Hallo Timo,

ergänzend zu dem vorher gesagten:

1. Ich hatte ja nur vermutet, dass Du bei der Aktivierung des Listeners kein Dokument offen hast. Oder den Fall: Der Benutzer schließt alle Dokumente. Dann sollte der Listener ja ohne Fehlermeldung einfach weiterlaufen.
Bis der Benutzer entscheidet das Panel zu schließen.

2. Um eine echte Fehlerbehandlung zu machen, könntest Du mit try-catch arbeiten um den Fehler zu untersuchen.

Falls kein Dokument geöffnet ist, wirft das hier einen Fehler:
Code
app.selection.length 


Welche Fehlernummer?

Code
try 
{
app.selection.length;
}
catch(e)
{
alert(e.number);
};

// 90884


Du könntest darauf reagieren, und den weiteren Code nicht ausführen.
Ob das für alle Situationen reicht? Möglicherweise nicht.

Code
#targetengine uwe-test 

app.addEventListener("afterSelectionChanged", doSomething);

function doSomething(evt)
{
try
{
app.selection.length;
}
catch(e)
{
if(e.number == 90884)
{

// Known error.

// e.message
// "Es sind keine Dokumente geöffnet."

// app.findKeyStrings("Es sind keine Dokumente geöffnet.")
// $ID/NoDocumentOpenError

return
};
else
{
alert( "Error: "+e.number +"\r"+ e.message );
return
};
}
};


Im Falle des Schließens eines Dokuments bekomme ich einen weiteren Fehler geworfen: "Es sind keine Dokumentenfenster geöffnet" mit Fehlernummer 90886.

Den könntest Du dann auch in die Kategorie der "bekannten" Fehler einordnen.
Vielleicht treten ja noch andere auf, die Du behandeln möchtest.

Also: Testen!
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

15. Jul 2017, 09:31
Bewertung:

gelesen: 8507

Beitrag als Lesezeichen
Kleine Korrektur meiner Formulierung:

"Es sind keine Dokumentenfenster geöffnet" muss heißen:
"Es sind keine Dokumentfenster geöffnet."
$ID/NoWindowOpenError

Dieser Fehler wird auch geworfen, wenn Du beispielsweise mit mehreren Fenstern eines Dokuments arbeitest und eines davon schließt. Ob Textansicht oder Layoutansicht macht keinen Unterschied.

Die Formulierung der Meldung ist ein wenig widersprüchlich. Könnte etwas präziser sein. "Das Fenster der Auswahl ist nicht mehr geöffnet." wäre vielleicht besser…

Experimentiere auch mal mit dem Seitenwerkzeug während der Listener läuft.
Weiss nicht, ob Du auch ausgewählte Seiten in Deinem Panel aufnehmen möchtest.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

17. Jul 2017, 16:55
Bewertung:

gelesen: 7540

Beitrag als Lesezeichen
Antwort auf: Hallo Uwe,

das mit dem IdleTask schaue ich mir mal.

Danke und Grüße
Timo


Hallo Timo,
hast Du neue Erkenntnisse?

afterSelectionChanged vs IdleTask

Die Hauptunterschiede dürften sein:

1. Mit der IdleTask fragst Du, bzw. kannst Du im Intervall abfragen wie es um die Auswahl bestellt ist. Und da InDesign im Moment der Abfrage "idle" ist, also nichts macht, wird der Anwender auch nicht ausgebremst. So jedenfalls die Theorie.

2. Mit dem afterSelectionChanged eventhandler wirst Du vermutlich stärker filtern müssen, wenn es um Textauswahlen geht. Es steht zu befürchten, dass das auf die Performance gehen könnte. Davon abgesehen: Du kannst den auch an das activeDocument hängen und musst ihn nicht unbedingt an der Application festmachen.

Was bei beiden passieren kann:
Wenn Du mal einen Zähler mitlaufen lässt, wirst Du feststellen, dass der handler mal "durchrutscht". Soll heißen, dass manche events zwar registriert, der Zähler hochgezählt, die Aktion im handler aber nicht ausgeführt wird. Ist mir bei meinen Tests jedenfalls so ergangen.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

tsone
Beiträge gesamt: 70

17. Jul 2017, 17:49
Bewertung:

gelesen: 5067

Beitrag als Lesezeichen
Hallo Uwe,

ich habe mich noch nicht weiter damit beschäftigen können. Scheint aber ne Wissenschaft für sich zu sein.

Muss mir noch überlegen, ob es für mich so überhaupt praktikabel ist, bzw. ob es meinen Arbeitsfluss unterstützt.

Trotzdem schon mal besten Dank an alle für die tolle Hilfe.

Grüße
Timo

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

18. Jul 2017, 11:43
Bewertung:

gelesen: 4860

Beitrag als Lesezeichen
Hallo Timo,
ja, das ist 'ne "Wissenschaft für sich"…

Ich würde mich jedenfalls auf regen Gedankenaustausch freuen, wenn Du Dich weiterhin mit diesem Thema beschäftigst. Der Testaufwand ist nicht unerheblich.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

drerol74
Beiträge gesamt: 507

18. Jul 2017, 13:01
Bewertung:

gelesen: 4835

Beitrag als Lesezeichen
Hallo Uwe,

ich hab's am Wochenende auch nochmal mit »After Selection Changed« ausprobiert, bei mir funktioniert das hier:

https://www.rolanddreger.net/...hp/s/5hpilI4FGNAQ6QT

index.html

Code
<!doctype html> 
<html>
<head>
<meta charset="utf-8"/>
<title>Interakives Panel</title>
<link rel="stylesheet" href="css/styles.css"/>
</head>
<body>
<div id="content">
<h1 id="constructor-name">Constructor erscheint hier ...</h1>
</div>
<script src="js/libs/CSInterface.js"></script>
<script src="js/main.js"></script>
</body>
<html>


indesign.jsx

Code
unction __main() { 

try {
var _externalObjLib = new ExternalObject("lib:\PlugPlugExternalObject");
} catch(_error) {
alert(_error);
}

if(!_externalObjLib) { return false; }

app.addEventListener(Application.AFTER_SELECTION_CHANGED, __afterSelectionChangeHandler);

return;
} /* END function __main */



function __afterSelectionChangeHandler(_event){

if(app.documents.length === 0 || app.layoutWindows.length === 0) { return false; }

var _selection;
var _constructorName;

_selection = app.selection;

if(!_selection || _selection.length === 0) {
_constructorName = "Es ist nichts ausgewählt.";
} else {
_constructorName = _selection[0].constructor.name;
}

var _csxsEventObj = new CSXSEvent();

_csxsEventObj.type = "idSelectionChanged";
_csxsEventObj.data = _constructorName;
_csxsEventObj.dispatch();

return;
} /* END function __afterSelectionChangeHandler */



main.js

Code
(function () { 

'use strict';

var _csInterface = new CSInterface();
var _output = document.getElementById("constructor-name");

_csInterface.addEventListener("idSelectionChanged", function(_event){
_output.innerHTML = _event.data;
});

_csInterface.evalScript("__main()");

}());


Schöne Grüße
Roland

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

18. Jul 2017, 20:00
Bewertung:

gelesen: 4753

Beitrag als Lesezeichen
Hallo Roland,
ja, ich dachte auch erst, dass das so funktioniert.

Teste mal mit dem Story-Editor oder mit einem zweiten Fenster des gleichen Dokuments. Schließe dann den Story-Editor oder das zweite Fenster. Das wird einen Fehler werfen, den Du nicht abfängst.

Ich denke, dass wir beim afterSelectionChanged eventhandler nicht um ein ordentliches try/catch herumkommen.

Hier mal ein ScriptUi-Window vom Typ Palette, das dies mit Deinem Code verdeutlicht:

Code
#targetengine uwe 

var c = 0;
var _constructorName = "Es ist nichts ausgewählt.";

var w = new Window("palette");
var myStaticText = w.add ("statictext", [0,0,200,50], c+" : "+_constructorName , {multiline: true});
w.show();

app.addEventListener(Application.AFTER_SELECTION_CHANGED, __afterSelectionChangeHandler);

function __afterSelectionChangeHandler(_event){

if(app.documents.length === 0 || app.layoutWindows.length === 0) { return };

var _selection;
var _constructorName;

_selection = app.selection;

if(!_selection || _selection.length === 0) {
_constructorName = "Es ist nichts ausgewählt.";
} else {
_constructorName = _selection[0].constructor.name;
}

myStaticText.text = c+" : "+_constructorName;
c++;
return;
} /* END function __afterSelectionChangeHandler */

*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

drerol74
Beiträge gesamt: 507

18. Jul 2017, 23:26
Bewertung:

gelesen: 4716

Beitrag als Lesezeichen
Du hast recht Uwe, da hat es was. Den Texteditor könnte man noch mit instanceof LayoutWindow abfangen, aber damit gibt es dann einen Fehler bei app.activeWindow.

Ich habe es jetzt mal damit versucht:

Code
_selection = app.layoutWindows[0].selection; 


statt

Code
_selection = app.selection; 



Mit dem Texteditor wird dann halt die aktuelle Auswahl nicht angezeigt. Muss mir das aber auch noch mal genauer ansehen, wenn etwas mehr Zeit ist.


Schöne Grüße
Roland

Interaktives Panel

drerol74
Beiträge gesamt: 507

19. Jul 2017, 00:26
Bewertung:

gelesen: 4693

Beitrag als Lesezeichen
Oder gleich das »layout« weglassen ...

Code
_selection = app.windows[0].selection; 

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

19. Jul 2017, 07:13
Bewertung:

gelesen: 4625

Beitrag als Lesezeichen
Hallo Roland,
was stört Dich an einem try/catch, das die beiden bekannten Fehler $ID/NoDocumentOpenError 90884 und $ID/NoWindowOpenError 90886 erkennt und abfängt und nur bei neuen Fehlern beispielsweise protokolliert?
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

19. Jul 2017, 07:41
Bewertung:

gelesen: 4622

Beitrag als Lesezeichen
Antwort auf: Oder gleich das »layout« weglassen ...

Code
_selection = app.windows[0].selection; 



Hallo Roland,
habe ich mal getestet.
Funktioniert tadellos.

EDIT:
Leider doch nicht. Hab' mich zu früh gefreut.
Mag an der Implementierung liegen.
*****
Mit herzlichem Gruß,
Uwe Laubender

(Dieser Beitrag wurde von Uwe Laubender am 19. Jul 2017, 07:57 geändert)

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

19. Jul 2017, 08:44
Bewertung:

gelesen: 4610

Beitrag als Lesezeichen
Es hatte an der Implementierung gelegen.

Hier die Version, die funktioniert.
Anmerkung: Ich benutze ein ScriptUI-Fenster vom Typ "palette" mit einem "statictext"-Element, das einen Rollbalken aufweist.

Der Rollbalken funktioniert mit CS6.
Aber nicht mehr mit CC oder höher.

Die Auswertung im Fenster enthält einen Zähler plus den Konstruktornamen aller ausgewählten Objekte. Das ist noch nicht sehr aussagekräftig für einen Anwender, dient nur dazu, das Konstrukt zu testen.

Code
#targetengine rolandsIdea 

var c = 0;

var w = new Window("palette");
var myStaticText =
w.add
(
"statictext",
[0,0,250,100],
c+" : "+"Es ist nichts ausgewählt." ,
{
multiline: true ,
scrolling : true // Will not work in CC and above. No scroll bar available.
}
);

w.show();

app.addEventListener(Application.AFTER_SELECTION_CHANGED, writeSelectionToPalette );

function writeSelectionToPalette(evt)
{
// Roland's idea:
if( app.documents.length == 0 || app.windows.length == 0 )
{
myStaticText.text = c+" : "+"Es ist nichts ausgewählt. Event A."
c++;
return
};
// Roland's idea:
var selection = app.windows[0].selection;

var result = [];

if(selection.length == 0)
{
myStaticText.text = c+" : "+"Es ist nichts ausgewählt. Event B." ;
c++
return
};

for(var n=0;n<selection.length;n++)
{
result[n] = c+" : "+selection[n].constructor.name
};

myStaticText.text = result.join("\r");

c++;
return;
};



Wobei ich sagen muss, dass ich mir noch nicht ganz sicher bin, weshalb das funktioniert und der Fehler $ID/NoWindowOpenError mit Nummer 90886 nicht geworfen wird.

Beim Schließen eines Storyeditor-Fensters konnte ich diesen in früheren Versionen provozieren. Diesmal nicht.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

drerol74
Beiträge gesamt: 507

19. Jul 2017, 23:28
Bewertung:

gelesen: 4547

Beitrag als Lesezeichen
Antwort auf: was stört Dich an einem try/catch, das die beiden bekannten Fehler $ID/NoDocumentOpenError 90884 und $ID/NoWindowOpenError 90886 erkennt und abfängt und nur bei neuen Fehlern beispielsweise protokolliert?


An sich spricht – denke ich – in diesem Fall nichts dagegen, mit try/catch den Fehler zu umgehen. Wenn das mit windows[0].selection ginge, wäre es halt kürzer.


Antwort auf: Wobei ich sagen muss, dass ich mir noch nicht ganz sicher bin, weshalb das funktioniert und der Fehler $ID/NoWindowOpenError mit Nummer 90886 nicht geworfen wird.



Ich hab testweise an windows[0] und windows[1] (bei 2 Fenstern eines Dokuments) die EventListeners AFTER_ACTIVATE und BEFORE_DEACTIVATE angehängt.

Beim Schließen von windows[1] feuert zuerst AFTER_SELECTION_CHANGED. app.selection ergibt zu diesem Zeitpunkt schon einen Fehler.

Code
app.windows[0].selection.toSource() // Ergebnis: [] 
app.windows[1].selection // Fehler: Object is invalid
app.windows[1] == null // Ergebnis: true


Danach löst BEFORE_DEACTIVATE von windows[1] aus und daraufhin AFTER_ACTIVATE von windows[0]. In Folge ist app.selection dann wieder gültig.

Das ist jetzt auch nur Spekulation, aber app.selection könnte eigentlich über windows[1] auf die aktuelle Auswahl zugreifen. Als aktives Fenster wird noch app.windows[1] geführt, obwohl es gar nicht mehr aktiv ist. Dieser Fehler wird aber in app.selection nicht abgefangen und bleibt es dann hängen.

app.windows[0].selection ist allerdings zu jedem Zeitpunkt gültig, egal, ob jetzt ein oder zwei Fenster geöffnet sind oder welches gerade den Index 0 hat.

Ich denke, das ist einfach ein blöder Bug.

Schöne Grüße
Roland

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

20. Jul 2017, 22:22
Bewertung:

gelesen: 4447

Beitrag als Lesezeichen
Hallo Roland,
hab Dank für's Testen. Ich muss aber mal nachfragen.

Zitat von Roland Ich hab testweise an windows[0] und windows[1] (bei 2 Fenstern eines Dokuments) die EventListeners AFTER_ACTIVATE und BEFORE_DEACTIVATE angehängt.


Ok.

Zitat von Roland Beim Schließen von windows[1] feuert zuerst AFTER_SELECTION_CHANGED. app.selection ergibt zu diesem Zeitpunkt schon einen Fehler.


Beim Schließen von windows[1] ? Also dasjenigen Fensters, das nicht das aktive ist? Das würde ich mal genauer begutachten wollen. Nur um nachzuvollziehen, wie Dein Versuchsaufbau war.

Hast Du das windows[1] per Mausklick über das UI geschlossen oder per Skriptbefehl mit windows[1].close() ?

Falls per Mausklick, wird ja dann windows[1] vermutlich kurzfristig zum aktiven Fenster.
Und erhält somit den index 0. Oder auch nicht. Siehe die Fälle A und B weiter unten.

Wir sollten an dieser Stelle erstmal Begrifflichkeiten klären.
Wenn Du von windows[0] und windows[1] sprichst, dann sprichst Du immer über die gleichen Fenster, oder?

Also Beispiel:

Dokument geöffnet. Zwei Fenster des gleichen Dokuments geöffnet.
Fenster 1: windows[0], das aktive Fenster mit Namen: Unbenannt-1:1 @ 50%
Fenster 2: windows[1], das nicht aktive Fenster: Unbenannt-1:2 @ 50%

Du schließt nun Fenster 2 per Mausklick. Wie?

A. Mit 2 Mausklicks?
Klick ins Fenster, um es dann mit einem zweiten Mausklick zu schließen?
Der Name von Fenster 1 ändert sich zu: Unbenannt-1 @ 53%

B. Mit 1 Mausklick?
Klick in das x des Tabs von Fenster 2 ?
Der Name von Fenster 1 ändert sich zu: Unbenannt-1 @ 53%

A. und B. könnten unterschiedliche Reihenfolgen von events auslösen.
Im Fall A ändert sich auch der Index des Fensters bis zum Zeitpunkt des Schließens zwingend. Bei B nicht.

Und ein weiterer Unterschied könnte sein, wenn Fenster 2 per methode close() geschlossen wird.
Könnte aber auch mit Fall B abgedeckt sein.

Vielleicht hab' ich ja am Wochenende ein weing Zeit, das genauer zu untersuchen.
Ich hoffe, mit meinen Fragen oder Bemerkungen nicht allzusehr zu verwirren.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

drerol74
Beiträge gesamt: 507

21. Jul 2017, 00:46
Bewertung:

gelesen: 4428

Beitrag als Lesezeichen
Hallo Uwe,

zur späten Stunden nur ganz kurz zum Ablauf:

Ich hab in meinem Fall dem linken Fenster (zu Beginn aktiv) durch das Skript Window.AFTER_ACTIVATE angehängt und dem rechten Fenster Window.BEFORE_DEACTIVATE (beide gleiches Dok). Dann wurde das rechte Fenster aktiviert und über das UI (x) geschlossen.

Die Überlegung war einfach die, dass immer eines der Fenster den Index 0 aufweisen muss, auch wenn dieser zwischen den Fenstern wechselt.

Ich muss mich jetzt für ein paar Tage aus der Diskussion ausklinken, Urlaub \o/, bin eigentlich schon gar nicht mehr da ;) Vielleicht hast du bis dahin schon Genaueres herausgefunden.

Schöne Grüße
Roland

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

24. Jul 2017, 08:15
Bewertung:

gelesen: 4169

Beitrag als Lesezeichen
Hallo Roland,
danke für die genauere Beschreibung.

Bei mir sieht es allerdings auch so aus als könnte ich mich die nächsten 14 Tage kaum um den Fall kümmern.

Aber vielleicht geht ja Timo noch mal ran an die Sache.

Dir wünsche ich einen schönen Urlaub!
Bei mir steht ein Umzug an. Zwar in der gleichen Stadt, aber trotzdem zeit- und nervenaufreibend. Lebe im Moment in einer Baustelle. Und das kann man wortwörtlich so nehmen.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Stephan_M
Beiträge gesamt: 480

21. Feb 2018, 00:07
Bewertung:

gelesen: 2134

Beitrag als Lesezeichen
Hallo Uwe,

dieses Thema trifft genau mein Problem, bei dem ich auch gerade hänge. Der "AfterSelectionChange"-Event tritt ein, wenn jemand ein Fenster schliesst - "app.selection" ist dann im EventHandler schon nicht mehr gültig. Gleiches Spiel mit app.activeDocument.
Du hast oben diese Try/Catch-Anweisung vorgeschlagen, um den Handler-Fehler abzufangen ... nur, bei mir stürtzt Indesign dann ab, wenn er es 'tried'! Läuft das bei Dir? Magst Du mir helfen?

(Ich werde wohl auch auf das Idle-Event gehen. Meh! Ist halt nicht so Echt-Zeit, aber wohl sinnvoll.)

Liebe Grüße,
Stephan

Hier mein Test-Script:
Code
#targetengine miscellaneous 
var w = new Window ("palette { text: 'Test Palette', preferredSize: [220,16], alignChildren:['fill','top']}");
w.sText = w.add( "statictext", undefined, 'Tell Selection' );

function getParas() {
if (app.documents.length == 0) {
desc = 'No documents are open.';
}
else {
try {
app.selection.length;
}
catch(e) {
if(e.number == 90884 || e.number == 90886) {
return "Closing"
};
else {
return "Error: "+e.number +"\r"+ e.message
};
}

try {
app.activeDocument;
}
catch(e) {
return "Error: "+e.number +"\r"+ e.message
};

var ad = app.activeDocument;
var s = app.selection;
}
return (s.length == 0)?('Nothing selected'):(s[0].constructor.name);
}


function updateSel() {
w.sText.text = getParas();
w.graphics.backgroundColor = w.graphics.newBrush (w.graphics.BrushType.SOLID_COLOR, [Math.random(), Math.random(), Math.random()]); // to show when updateSel is called
}


app.eventListeners.add("afterSelectionChanged", updateSel,{name:'paraStyleChanger_selChange'});

w.onClose = function() { app.eventListeners.itemByName('paraStyleChanger_selChange').remove();}
w.show();

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

21. Feb 2018, 10:19
Bewertung:

gelesen: 2072

Beitrag als Lesezeichen
Hallo Stephan,
deinen Code hab' ich noch nicht getestet.
Mit welchem InDesign hast Du's probiert?

Da bei Dir bereits bei app.selection.length == 0 der Absturz kommt, kann ich an dieser Stelle einen Bug vermuten. Vielleicht funktionieren alternative Schreibweisen und ein sich Herantasten?

Sollte keinen Unterschied machen, aber wer weiß?:
Code
app.properties.selection.toString() == "" 


Vielleicht hilf ja auch das event-Objekt zu untersuchen?
Möglich, dass da was Brauchbares vorhanden ist.

Code
function updateSel( event ) 
{
var x , e ;
for( x in event )
{
try{ $.writeln( x +"\t"+ event[x].toString() ) }
catch(e){ $.writeln( x +"\t"+ e.message ) };
};
};

*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

21. Feb 2018, 13:20
Bewertung:

gelesen: 777

Beitrag als Lesezeichen
Hallo Stephan,
hab' mal einen Kurztest mit Deinem Code und InDesign CC 2018 gestartet.
Bisher keine Abstürze. Auch nicht nach Schließen von irgendwelchen Layout-Windows.

Problem allerdings: Das Dialogfeld kann hinter den Anwendungsrahmen geraten.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Stephan_M
Beiträge gesamt: 480

21. Feb 2018, 23:54
Bewertung:

gelesen: 750

Beitrag als Lesezeichen
Danke Uwe, für das Testen und den Hinweis daß es bei Dir läuft. Habe mich dadurch erst dran gemacht nach Außen zu schauen, zwei Plugins und drei Autostartskripte entfernt... am Ende war es Rorohikos "StoryParker", daß im Zusammenspiel mit dem Testskript Indesign reproduzierbar einfror. Schon komisch.

Jetzt kann ich weiter machen. Dein Abfangen/Umwandeln der Event-Error-Messages hat mir auch geholfen. Und jetzt teste ich mal parallel, ob's mit dem Idle-Task eh eine bessere Lösung wird.

Hast mir geholfen!

Herzliche Grüße,
Stephan

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

22. Feb 2018, 07:49
Bewertung:

gelesen: 733

Beitrag als Lesezeichen
Antwort auf: … am Ende war es Rorohikos "StoryParker", daß im Zusammenspiel mit dem Testskript Indesign reproduzierbar einfror. Schon komisch. …


Aha!
Na, dann würde ich mal Kris Coppieters von Rorohiko davon unterrichten.
*****
Mit herzlichem Gruß,
Uwe Laubender

Interaktives Panel

Stephan_M
Beiträge gesamt: 480

22. Feb 2018, 21:11
Bewertung:

gelesen: 697

Beitrag als Lesezeichen
Mach ich.

Hier noch die schnelle rescourcenschonenden verquickung des 'idleTasks' mit 'afterSelectionChanged' ...

Wenn die Selection sich ändert geht eine Flagge hoch. Und beim ersten Leerlauf guckt der Eventhandler erstmal nach der Flagge ob's überhaupt eine Veränderung abzuarbeiten gab. Wenn sich die Selection also sehr schnell und häufig ändert, dann wird darauf frühestens beim nächsten Leerlauf reagiert. Das ist toll, bei z.B. Texteingaben (insertion points).

Danke dafür, Uwe!

Code
#targetengine miscellaneous 
var w = new Window ("palette { text: 'Test Palette', preferredSize: [220,16], alignChildren:['fill','top']}");

w.sText = w.add( "statictext", undefined, 'Tell Selection' );
w.sText.needs_update = new Boolean;

function getParas() {
if (app.documents.length == 0) {
return "No documents are open.";
}
else {
try {
var ad = app.activeDocument;
var s = app.selection;
}
catch(e) {
if(e.number == 90884 || e.number == 90886) {
return "Closed Window"
};
else {
return "Error: "+e.number +"\r"+ e.message
};
}
}
return (s.length == 0)?('Nothing selected'):(s[0].constructor.name);
}


function updateSel(event) {
if (w.sText.needs_update) {
w.sText.text = getParas();
w.graphics.backgroundColor = w.graphics.newBrush (w.graphics.BrushType.SOLID_COLOR, [Math.random(), Math.random(), Math.random()]); // to show when updateSel is called
w.sText.needs_update = false;
}
}

app.eventListeners.add("afterSelectionChanged", function (){w.sText.needs_update = true;},{name:'paraStyleChanger_selChange'});

app.idleTasks.add ({name : "paraStyleChanger_idleTask" , sleep : 1000 }).addEventListener( IdleEvent.ON_IDLE , updateSel , false);

w.onClose = function() {
app.idleTasks.itemByName('paraStyleChanger_idleTask').remove();
app.eventListeners.itemByName('paraStyleChanger_selChange').remove();
}
w.show();

Interaktives Panel

Uwe Laubender
Beiträge gesamt: 5319

23. Feb 2018, 10:10
Bewertung:

gelesen: 670

Beitrag als Lesezeichen
Hallo Stephan,
kleine Anmerkung zu Deinen Skriptzeilen:

Du kannst die else-Ummantelung des folgenden Codes bei Deiner ersten if-Abfrage weglassen. Bei einem return wird der folgende Code nicht ausgeführt.

Ebenso innerhalb des catch(), da Du dort mit return "Closed Window" die folgenden Codeausführung unterdrückst.

Hab Dein Skript noch nicht laufen lassen.
Werde rückmelden, wenn mir noch was auffällt.
*****
Mit herzlichem Gruß,
Uwe Laubender