ich habe ein Script erstellt, dass mir Texte aus einer Word-Datei positioniert und anhand den Spaltenvorgaben der aktuellen Seiten als einzelne miteinander verketteten Textblöcke positioniert. So weit, so schön ...
Allerdings greife ich die Seite, auf der mit dem Positionieren angefangen werden soll, über app.activeWindow.activePage ab, was zu keinem befriedigenden Ergebnis führt, da ID und ich unterschiedliche Ansichten über das Thema haben.
Mir wäre es am liebsten, dass ich mit der Maus auf eine beliebige Seite klicke und das Script dann dort startet. Derzeit ist es so, dass ID die Seite nimmt, die (frei übersetzt) am "meisten vorne" ist. Auch mit rechts und links gibt es Probleme.
Nun die Frage: Gibt es einen Eventhandler oder ähnliches, über dessen Eigenschaften/Funktionen man den letzten Klick abfragen kann?
Das Skript erstellt temporär einen Rechteckrahmen, der als IDMS-Datei exportiert wird und anschließend in die Placegun geladen wird. Klickst Du nun auf eine Seite wird dort der Rahmen erstellt. Die Seite ist direkt auslesbar über app.selection[0].parentPage. ***** Mit herzlichem Gruß, Uwe Laubender
Genausogut könntest Du als Auswahlwerkzeug das Seitenwerkzeug nehmen. app.selection[0] gibt dann die ausgewählte Seite zurück.
Falls Du auf einer Auswahl der Seite im Seitenmenü bestehst, dann schau' Dir mal meine Beiträge zum Thema im amerikanischen InDesign-Scripting-Forum an:
Wie halte ich mein Script an, bis die PlaceGun positioniert wurde?
Bei Dateipositionierungen kann ich über true/false abfragen. Derzeit wird zwar meine PlaceGun geladen, aber im Hintergund arbeitet mein Script weiter und will auf das rectangle zugreifen, das sich aber noch in der PlaceGun befindet.
Theoretisch kannst Du den Status "placeGuns.loaded" abfragen.
Praktisch kannst Du das Skript aber nach dem Laden der PlaceGun nicht unterbrechen, um zwischenrein 'was abzulegen und dann mit dem Skript fortzufahren - oder doch?
Gute Frage. Wie wär's mit einem eventlistening-Mechanismus, der nach afterPlace schaut? Das Objekt in der placegun könnte einen speziellen Namen enthalten, falls sich der Anwender entscheidet nach dem Skriptstart noch mehr Objekte zu laden. ***** Mit herzlichem Gruß, Uwe Laubender
Habe mich jetzt mal mit den EventListenern beschäftigt und es so gelöst:
#target indesign-10 #targetengine "mySession"
var gO = {};
main();
function main() { var newRect = app.activeWindow.activePage.rectangles.add(); var rectFile = File("~/Desktop/rec.idms") newRect.exportFile(ExportFormat.INDESIGN_SNIPPET, rectFile); newRect.remove(); gO.placeGunListenerID = app.activeDocument.eventListeners.add("afterPlace", listenerTest).id; app.activeDocument.placeGuns.loadPlaceGun(rectFile); $.writeln("Fertig mit Hauptprogramm"); }
function listenerTest () { $.writeln("Aufruf des weiteren Teils nach der Platzierung"); if(app.activeDocument.eventListeners.itemByID(gO.placeGunListenerID).isValid) { app.activeDocument.eventListeners.itemByID(gO.placeGunListenerID).remove(); } }
Hierzu gleich wieder zwei Fragen: 1) Wie kann ich das ohne diese globale Variable lösen? Würde eigentlich gerne die Listener-ID in die aufgerufene Funktion übergeben. 2) Kann man eine targetEngine zurücksetzen?
so ganz habe ich die Funktion Deined Skriptes nicht verstanden, und Dein Listener wird am Ende nicht gelöscht.
Ich habe Deinen Code etwas umgeschrieben:
#target indesign-13 #targetengine "mySession"
placeGunTest = new PlaceGunTest(); alert(placeGunTest); placeGunTest.removeListener(); placeGunTest = undefined; PlaceGunTest = undefined; alert(PlaceGunTest==undefined); alert(placeGunTest==undefined); /*Object*/function PlaceGunTest() { var /*Rectangle*/newRect = app.activeWindow.activePage.rectangles.add(), /*File*/rectFile = File("~/Desktop/rec.idms"), /*Int*/placeGunListener; newRect = app.activeWindow.activePage.rectangles.add(); newRect.exportFile(ExportFormat.INDESIGN_SNIPPET, rectFile); newRect.remove(); /*EventListener*/placeGunListener = app.activeDocument.eventListeners.add("afterPlace", listenerTest); app.activeDocument.placeGuns.loadPlaceGun(rectFile); $.writeln("Constructor executed"); function listenerTest () { $.writeln("Aufruf des weiteren Teils nach der Platzierung"); } this.removeListener = function(){ if(placeGunListener != null) placeGunListener.remove(); } }
Ich erzeuge in der Funktion PlaceGunTest ein Object mit Constructor, der Deinen Code ausführt und die Methode removeListener zum Löschen des Listeners zur Verfogung stellt. Damit ereiche ich, dass alle Variablen innerhalb des Objektes sichtbar sind und Methode removeListener von außen aufzurufen ist.
placeGunTest = new PlaceGunTest();
erzeugt ein neues Objekt in placeGunText und führt den Constructorbereich aus.
Hallo Werner, Danke erstmal und ich habe das mal ausprobiert. Bei Deinem Vorschlag wird in der ESTK-Konsole zwar "Constructor executed" ausgegeben, nicht aber "Aufruf des weiteren Teils nach der Platzierung". Deutet für mich darauf hin, dass die Funktion listenerTest nicht ausgeführt wird. In dieser will ich aber den ganzen anderen Kram nach der Positionierung ausführen.
weg! ;-) Und wenn Du wirklich nur die Seite brauchst, kann man da natürlich noch einiges verbessern. Der Listener darf erst entfernt werden, wenn die Platzierung erfolgt ist. Ich würde ihn also nur einmal laden und erst entfernen, wenn die komplette Arbeit abgeschlossen ist.
Und noch eine Frage: Wie halte ich mein Script an, bis die PlaceGun positioniert wurde?…
Gute Frage. Wie wär's mit einem eventlistening-Mechanismus, der nach afterPlace schaut? Das Objekt in der placegun könnte einen speziellen Namen enthalten, falls sich der Anwender entscheidet nach dem Skriptstart noch mehr Objekte zu laden.
Hallo Uwe,
wie weise ich denn dem platzierten Objekt einen Namen zu oder kann es identifizieren?
Das Resultat aus loadPlaceGun ist undefined und ich kann der Funktion nur die Datei und true/false für das Zeigen des Öffnen-Dialogs übergeben.
das platzierte Objekt ist bei mir selectiert, Du kannst also app.selection[0] einen Namen, oder besser ein Label zuweisen. Mit dem hinzufügen eines Labels kannst Du auch mehrere Informationen hinterlassen.
Das erzeugte Rectangle bekommt irgendeinen kryptischen eindeutigen Namen, bevor ich es als IDMS exportiere. Darüber finde ich es auch nach dem Rückimport zuverlässig wieder.
Komisch, dass die PlaceGun einem das nicht automatisch als Wert zurückgibt.
Irgendwie habe ich geahnt, dass diese Listener-Nummer wieder komplizierter wird als erhofft.
Bei folgendem Code wird nur ausgegeben: "Fertig mit Hauptprogramm"
Offensichtlich ist das Script nicht geeignet, in die mit afterPlace aufgerufene Funktion listenerTest zu gehen. Wäre dem so, sollte ja zumindest "Aufruf des weiteren Teils nach der Platzierung" ausgegeben werden.
Hat jemand eine Ahnung, was ich falsch gemacht habe?
#target indesign-10 #targetengine "mySession3"
var gO = {};
main();
function main() { var newRect = app.activeWindow.activePage.rectangles.add(); newRect.name = "myRectangleForExportImport"; var rectFile = File("~/Desktop/rec.idms") newRect.exportFile(ExportFormat.INDESIGN_SNIPPET, rectFile); gO.placeGunListener = app.activeDocument.placeGuns.addEventListener("afterPlace", listenerTest); app.activeDocument.placeGuns.loadPlaceGun(rectFile); $.writeln("Fertig mit Hauptprogramm"); }
function listenerTest() { $.writeln("Aufruf des weiteren Teils nach der Platzierung"); var myRect = app.activeDocument.pageItems.itemByName("myRectangleForExportImport"); if(myRect.isValid) { $.writeln("PlaceGun wurde positioniert auf Seite " + app.selection[0].parentPage.name + " an Stelle x = " + app.selection[0].geometricBounds[1] + " / y = " + app.selection[0].geometricBounds[0]); } myRect.remove(); if(gO.placeGunListener.isValid) { app.activeDocument.placeGuns.removeEventListener("afterPlace", listenerTest); } }
function listenerTest () { $.writeln("Aufruf des weiteren Teils nach der Platzierung"); newRect = app.activeWindow.activePage.rectangles.add() newRect.remove(); app.activeDocument.placeGuns.loadPlaceGun(rectFile); // this.activePage = newRect.parentPage; // use this to get last parentPage outside of object in same session $.writeln( "Aufruf des weiteren Teils nach der Platzierung:\n" + app.selection[0].parentPage.name + " an Stelle x = " + app.selection[0].geometricBounds[1] + " / y = " + app.selection[0].geometricBounds[0] ); newRect.remove(); } this.removeListener = function(){ if(placeGunListener != null) placeGunListener.remove(); } this.cleanUp = function(){ this.removeListener(); app.activeDocument.placeGuns.abortPlaceGun(); } } [b]// execute this AFTER getting Page or AFTER done whole work! [b]/* [b] placeGunTest.cleanUp(); [b] delete $.global.placeGunTest */
"nicht gelesen" trifft es nicht, "nicht verstanden" war es leider :-)
Wenn ich Dein Script in einem frisch gestarteten ID in einem neuen Dokument laufen lasse, bekomme ich die Meldung:
"Ein angehängtes Script hat den folgenden Fehler verursacht:Die angeforderte Aktion konnte nicht ausgeführt werden, da das Objekt nicht mehr existiert. Möchten Sie diesen Ereignis-Handler deaktivieren?""
Weiterhin interessant ist der Ablauf: - Das Script läuft im ersten Teil durch. - Ich habe eine geladene PlaceGun, die ich positioniere. - Es kommt im ID der Fehler, den ich wegclicke. - Danach habe ich wieder eine geladene PlaceGun, die ich positinieren kann. - Im Estk wird der Wert der ersten PlaceGun ausgegeben. - Danach habe ich drei Rectangles auf der Seite, wo eigentlich keins mehr sein sollte.
Da ich den Aufbau nicht verstehe, wage ich mich auch nicht an die Fehlersuche.
Warum läuft denn bei Dir das Script korrekt?
Um den Sinn nocheinmal konkret zu formulieren: Ich möchte für den weiteren ABlauf im ID nur wissen, auf welcher Seite an welcher Position der Anwender geklickt hat. Die Rectangles brauche ich nicht.
Um den Sinn nocheinmal konkret zu formulieren: Ich möchte für den weiteren ABlauf im ID nur wissen, auf welcher Seite an welcher Position der Anwender geklickt hat.
So leid es mir tut, ich habe den weiteren Ablauf immer noch nicht begriffen! Zuerst einmal, Thema dieses Feeds ist: Auf welche Seite wurde zuletzt geklickt? In Deinem Beispiel fragst Du aber auch die Position des Rechtecks ab. Willst Du also nur die Seite, oder auch die genau Position wissen? Wie willst Du das Ergebnis auswerten und weiterverarbeiten? Zur Zeit gehe ich davon aus, dass Du eine ganze Reihe von Klicks auswerten willst, deshalb liefere ich ein Ergebnis und lade die PlaceGun neu und warte auf den nächsten Klick. Dieses warten musst Du explizit durch den Aufruf der Methode cleanUp() beenden. Auch das Beenden von InDesign räumt auf.
"Ein angehängtes Script hat den folgenden Fehler verursacht:Die angeforderte Aktion konnte nicht ausgeführt werden, da das Objekt nicht mehr existiert. Möchten Sie diesen Ereignis-Handler deaktivieren?""
Bei mir passiert das nicht, das müssten wir dann mal im SingleStep-Verfahren und mit einem Errorhandler einkreisen. - Die Fehlermöglichkeiten sind beinahe unendlich groß und müssen gezielt abgefangen werden. Ursache könnten die Voreinstellungen sein.
Danach habe ich drei Rectangles auf der Seite, wo eigentlich keins mehr sein sollte.
Wie so oft in InDesign könnte es sein, dass der Eventhandler nach einer Platzierung mehrfach aufgerufen wird, in solch einem Fall muss der Eventhandler so etwas gezielt verhindern. Um das Problem weiter einzukreisen wäre Deine InDesign-Datei hilfreich. Außerdem sollten wir das Skript mit unterschiedlichen InDesign-Versionen prüfen. Auf jeden Fall muss ich zuerst einmal den ganzen Ablauf Deiner Aufgabe verstehen. Muss Dein Skript auf eine Anwenderaktion reagieren, oder benötigst Du nur eine sichere Methode der Erkennung, auf welcher Seite Du gerade stehst? Im letzteren Fall würde doch eigentlich die parentPage der aktuellen Selektion ausreichen, oder?
function listenerTest () { $.writeln("Aufruf des weiteren Teils nach der Platzierung"); app.activeDocument.placeGuns.loadPlaceGun(rectFile); // this.activePage = newRect.parentPage; // use this to get last parentPage outside of object in same session $.writeln( "Aufruf des weiteren Teils nach der Platzierung:\n" + app.selection[0].parentPage.name + " an Stelle x = " + app.selection[0].geometricBounds[1] + " / y = " + app.selection[0].geometricBounds[0] ); } this.removeListener = function(){ if(placeGunListener != null) placeGunListener.remove(); } this.cleanUp = function(){ this.removeListener(); app.activeDocument.placeGuns.abortPlaceGun(); } } // execute this AFTER getting Page! /* placeGunTest.cleanUp(); delete $.global.placeGunTest */
while (o != null) { if ("parentPage" in o) return o.parentPage; var whatIsIt = o.constructor; switch (whatIsIt) { case Page : return o; case Character : o = o.parentTextFrames[0]; break; case Footnote :; // drop through case Cell : o = o.insertionPoints[0].parentTextFrames[0]; break; case Note : o = o.storyOffset.parentTextFrames[0]; break; case XMLElement : if (o.insertionPoints[0] != null) { o = o.insertionPoints[0].parentTextFrames[0]; break; } case Application : return null; default: o = o.parent; } if (o == null) return null; } return o } catch (error) { alert(error.message + "\nin File: " + error.fileName + "\nZeile: " + error.line); // throw error; } return null; } } // execute this AFTER getting Page! /* afterSelectionChanged.removeListener(); delete $.global.removeListener */
1) Wenn ich das letzte Skript laufen lasse, wird im ESTK nie ausgegeben "Constructor executed". Also läuft die Funktion AfterSelectionChanged nie zu Ende.
2) Der PlaceGun-Handler ist danach immer aktiv.
3) Diesen Thread habe ich mit der Frage gestartet "Aufwelche Seite wurde zuletzt geclickt?". Durch eine Idee von Uwe bin ich da drauf gekommen, auch noch die Position des Clicks abzufragen.
Ich möchte nicht, dass anch jedem Positionieren das Script ausgeführt wird. Ich will nur nach Aufruf des Scripts ein weiteres Script aufrufen, dass mir auf der Seite an einer bestimmten Stelle ein Word-Doc positioniert. Mit diesem mache ich dann bestimmte Dinge: - Doppelte Leerzeichen entfernen - Richtige Gedankenstriche und Anführungszeichen einsetzen. - Im Word-Doc eingebettete Bilder unembedden, an bestimmter Stelle abspeichern und an der ursprünglichen Stelle wieder einsetzen. Alle letztgenannten Punkte funktionieren problemlos.
Durch Uwe bin ich darauf gekommen, dass ich das Word-Doc nicht nur auf einer bestimmten Seite sondern auch in einer bestimmten Spalte und mit einem definierten Versatz von oben beginnen lassen könnte.
Kurz gesagt brauche ich eine Funktion, die ich wahlweise aufrufen kann und die danach wieder deaktiviert wird. Als Ergebnis brauche ich diese Parameter: - Seite - x-Wert - y-Wert
1) Wenn ich das letzte Skript laufen lasse, wird im ESTK nie ausgegeben "Constructor executed". Also läuft die Funktion AfterSelectionChanged nie zu Ende.
Kein Bug, sondern Feature!
2) Der PlaceGun-Handler ist danach immer aktiv.
Kein Bug, sondern Feature!
Ich ging davon aus, dass Du viele Dateien automatisch nacheinander abarbeiten woltest. Aber offensichtlich willst Du nur immer eine Datei bearbeiten. Ich denke, dass Du dafür eigentlich keinen Eventhandler benötigst, denn Du musst ja in diesem Fall jedesmal ein Skript starten. Dennoch mache ich jetzt mal mit Deinem Ansatz weiter:
#target indesign-13 #targetengine "mySession"
placeGunTest = new PlaceGunTest(); delete $.global.placeGunTest;
According to the Object Model Viewer, LayoutWindow.activePage is said to return "The front-most page." I could not make any sense out of that sentence.
It seems to work this way:
When you are on a spread, activePage returns the page that is most exposed, including areas to the right or left. So if I have a two-sided spread, and zoom out to see the whole spread, with the spine in the middle of the screen, activePage returns the left page if I scroll an inch to the left (getting the spine to the right of the middle), and vice versa.
It doesn't matter whether I've selected an item on one of the pages. That does not matter when it concerns activePage. I was convinced that selections mattered, but obviously not and I realize I must have used this erroneous approach for many years. Will need to pick up the parent page of the selection instead.
Just informing about this, since it may be an easy mistake to make.