Feld "Erstellt am" per Script füllen

und natürlich kann man spielen; dieses Skript akzeptiert sowohl YYYY-MM-TT als auch YYYYMMTT (auch wenn ich befürchte, dass ich das wahrscheinlich umständlicher als nötig erreicht habe; ich bin AS anstatt JS gewohnt, und da ist alles umständlich :see_no_evil:)

function performsmartrule(records){ 
let app = Application("DEVONthink 3");
records.forEach(r => {
  let name = r.name();
  let dateFull = name.match(/^(\d{4})-(\d\d)-(\d\d)/);
  if (dateFull !== null) {
  let creationDate = new Date(dateFull[1],dateFull[2]-1,dateFull[3]);
  r.creationDate = creationDate;
  } else {
  let dateFull = name.match(/^(\d{4})(\d\d)(\d\d)/);
  if (dateFull !== null) {
  let creationDate = new Date(dateFull[1],dateFull[2]-1,dateFull[3]);
  r.creationDate = creationDate;
  }}
})
}

Danke fürs zusammenbauen Blanc! Es funktioniert genau so wie es soll =)

Den von dir geposteten Link habe ich angeschaut. Ich hätte nicht gedacht, dass sich der Code so leicht adaptieren lässt. Vorausgesetzt man weiß wo genau die Klammern hin müssen :wink:

Das Skript im entsprechenden Format posten werde ich mir fürs nächste mal zu Herzen nehmen.

1 Like

Endlich, ein Verbündeter! :crazy_face:

In absteigender „badness“

  • gar keine Angabe, also app =: globale Variable, implizit dasselbe wie
  • var app =: app ist eine Variable, die überall in der Datei sichtbar und modifizierbar ist. Auch vor der Definition. Ganz schlecht, wenn sich der Wert nicht ändern sollte.
  • let app=: app ist nur im umschließenden Block definiert und kann nur darin verändert werden.
  • const app=: app ist nur im umschließenden Bock definiert und kann nicht modifiziert werden.

Blöcke sind Funktionen, Schleifen und Conditionals (if etc). Was außerhalb einer Funktion, etwa am Anfang der Datei, deklariert wird, ist überall sichtbar. Was in einer Funktion mit let oder const deklariert wird, ist nur innerhalb dieser Funktion sichtbar.

Grundsätzlich sollte man const benutzen, wenn sich der Wert nicht verändern kann. Was sehr oft der Fall ist.

Edit: TL;DR

Nochmal etwas genauer. Früher kannte JavaScript nur globale Variable, es gab weder var noch let oder const. So ähnlich wie Basic (oder AppleScript?). Das war natürlich nicht wirklich zeitgemäß. Also kam zuerst var – keine semantische Verbesserung, aber syntaktischer Zucker. Außerdem konnte man in Verbindung mit "use strict"; erzwingen, dass jede Variable deklariert werden musste.

Dann kam let, das die Sichtbarkeit von Variablen auf Blöcke beschränkt. D.h. in

for (let i = 0; i < 5; i++) {…}
console.log(i);

wirft die zweite Zeile einen Fehler, weil es i nicht mehr gibt. Andererseits gilt für

let i = 2;
for (let i = 0 ; i < 5; i++) {...}

dass das for einen Fehler wirft, weil i schon deklariert ist, und zwar im umschließenden Block. In diesem Fall würde man mit for (i = 0 ; i < 5; i++) {...} den Fehler beim Übersetzen vermeiden, aber vermutlich einen semantischen einbauen, denn am Ende der Schleife hätte i den Wert 5.

Für const gelten dieselben Sichtbarkeitsregeln wie für let. Zusätzlich wenig überraschend: Man kann eine mit const deklarierte Variable nicht ändern. Wobei …
const a = 5; a = 6 mag der Compiler nicht. Aber
const a = [], a[0] = 1 ist kein Problem. Denn man ändert nicht a, sondern nur dessen Inhalt. Oder so. Dasselbe gilt für andere Objekte, aber nicht für Strings.

Und: Innerhalb von Schleifen darf man const-Werte redeklarieren:

record.forEach(r => {
  const t = record.plainText();
}

ist also erlaubt (und erwünscht).

2 Likes

Danke Großer :pray:

Hallo Zusammen,
interessante Entwicklung hier im Thread. Ich bin begeistert… Allerdings habe ich von JavaScript nun so gar keine Ahnung…
Darum würde ich mir wünschen - wenn es das “Grundgerüst” ja nun schon gibt - das Script noch ein wenig “aufzupumpen”.
Ich würde gerne die Möglichkeit haben, dass man in einer Datenbank / Gruppe eine Liste rausfiltern kann, die alle Dokumente rauswirft, wo das am DateinamenAnfang stehende Datum im Format: YYYYMMTT_ nicht mit dem Erstellungsdatum übereinstimmt. Ist das mit halbwegs vertretbarem Aufwand möglich?
Es wäre echt toll, wenn jemand wissendes sich dem widmen könnte.
Ich hoffe sehr, dass ich mit dem Wunsch nicht “überziehe” und falls doch… Sorry, ich weiss leider nicht was der Wunsch in “Codezeilen” bedeutet…
Danke im Voraus…
Für´s Feedback vielen Dank im Voraus.

HG

Rolf

Nach meiner Erfahrung hier ist es wenig zielführend, Scripts für die speziellen Anforderungen einzelner zu schreiben. Früher oder später wirst du andere Wünsche haben, und wer erfüllt dir die dann?

Aus meiner Sicht ist es sinnvoller, sich selbst damit zu beschäftigen und konkrete Fragen zu stellen, wenn es nicht mehr weitergeht. Beispiele für Scripts sind hier und auf Scripting with JXA | JavaScript for Automation (JXA) in großer Zahl zu finden. Und das Web ist voll mit Erklärungen zu Javascript.

https://bru6.de/JXA

Unter https://bru6.de/JXA kommt ein 404. https://bru6.de/jxa funktioniert.

Ohne Anspruch auf Vollständigkeit:

Geschweifte Klammern {} müssen um Funktionen (dh um den Funktionskörper):

function bla() {
// Code hier
}

und runde Klammern () um die Argumente der Funktion/Methode sowohl bei der Definition (s.o.) als auch beim Aufruf: bla(). Und das gilt auch, wenn es gar keine Parameter gibt!

Außerdem braucht man geschweifte Klammern bei Blöcken mit if, while, for: if (i === 5) { // Code } usw. Das ist strenggenommen nicht nötig, wenn der Code nur aus einer Zeile besteht, man sollte aber wegen der besseren Lesbarkeit immer klammern.

Auch Objekt-Definitionen brauchen geschweifte Klammern: const bla = {fasel : 1, blub: "ja"}

Eckige Klammern [] kommen mE nur beim Indizieren und Deklarieren von Arrays vor:
const a = [1,3,5]; const b = a[1] // b ist 3

Grausam wird es bei den selbst-ausführenden anonymen Funktionen:

(() => {
// code
})

definiert eine Funktion ohne Namen (anonym) und ohne Parameter (()). Letzteres ist nicht zwingend, btw. In dieser Form ergibt das wenig Sinn. Schreibt man jedoch direkt nach dieser Definition nochmal (), wird die gerade definierte Funktion sofort ausgeführt. Dieses Konstrukt ist häufig zu sehen, wenn jemand eine Funktion braucht, die direkt nach dem Laden des Scripts läuft.

Tatsächlich sind die Klammern wohl vor allem für jene irritierend, die von Basic, Applescript, Smalltalk o.ä. Sprachen kommen. In den meisten aktuellen Sprachen sind Klammern üblich und nützlich. Wenn auch vielleicht manchmal etwas kryptisch.

Danke. Da hat mich die Autokorrektur gebissen.

Wie kann ich die Datumsänderungen auf alle Untergruppen (NUR Gruppen, KEINE andere Art von Objekten) anwenden? Mit Apple Script bekomme ich das hin, aber bei Java Script muss ich mich noch einarbeiten.

Hat jmd. einen Tipp für mich, wie eine Schleife mit JS aussehen könnte, welche NUR die Untergruppen einbezieht?

Danke im Voraus…
Chris

BTW:

Mit Apple Script kann man auch Untergruppen wie folgt “bearbeiten”… zB den Lock-Status setzen:

tell application id "DNtp"
	try
		set this_selection to the selection
		if this_selection is {} then error "Please select some contents."
		my lockItems(this_selection)
	on error error_message number error_number
		if the error_number is not -128 then display alert "DEVONthink" message error_message as warning
	end try
end tell

on lockItems(theseRecords)
	local this_record
	tell application id "DNtp"
		repeat with this_record in theseRecords
			set locking of this_record to true
			if type of this_record is group then my lockItems(children of this_record)
		end repeat
	end tell
end lockItems

Ich bin nicht am Mac, deshalb ist das Folgende mit Vorsicht zu genießen!

Mit children.whose oder content.whose könnte man versuchen, nach Gruppen zu filtern. Es sollte hier im Forum ein Beispiel geben, wie man das in JavaScript mit type nutzt. Sonst auf Scripting with JXA | JavaScript for Automation (JXA)

Ich weiß jetzt nicht genau, was Du mit “die Datumsänderungen” meinst (angesichts der Länge dieses Threads und seines Alters wäre die Frage womöglich in einem neuen Thread besser aufgehoben gewesen).

Angenommen, Du hast eine Sammlung von records, z.B. aus app.selectedRecords().
(@blanc: bitte setz’ deine Klammerfilterbrille auf, akute Klammeritis voraus). Dann liefert Dir

records.whose({ _match: [ObjectSpecifier().type, "group"] })()

die Teilmenge derjenigen Records, die vom Typ “group” sind, und zwar als JavaScript-Array. Also könntest Du sowas wie

gruppen = records.whose({ _match: [ObjectSpecifier().type, "group"] })();
gruppen.forEach(g => {
  /* Hier die einzelnen Gruppen verarbeiten */
})

benutzen, um diese Gruppen zu verarbeiten. Das Filtern mit whose ist schnell und elegant (naja, es wäre noch eleganter, wenn man nicht diesen Quatsch mit ObjectSpecifier().type hinschreiben müsste), und Du kannst es auf jede Art von Listen in der Scripting-Umgebung anwenden. Also z.B. auch auf app.databases["Meine Datenbank"].content

1 Like

Wenn es nur darum geht, das geschilderte Problem zu lösen, so möchte ich mir den Hinweis erlauben, das DT3 auch mit AppleScript arbeitet.

Danke erstmal für deinen Hinweis…, Eigentlich möchte ich bei einer neu indizierten Gruppe (und deren Untergruppen) unter anderem das Erstellungsdatum und das Änderungsdatum auf das aktuelle Datum setzen. Das funktioniert auf bei der (Haupt-) Gruppe einfach mit:

function performsmartrule(records){ 
let app = Application("DEVONthink 3");
records.forEach(r => {
	r.date = new Date();
	}
	)
}

oder zB mit den folgenden Zeilen jeweils einzeln:

function performsmartrule(records){ 
let app = Application("DEVONthink 3");
records.forEach(r => {
	let creationDate = new Date();
	r.creationDate = creationDate;
	r.modificationDate = creationDate;
	}
	)
}

Ich möchte dies nun auch auf die Untergruppen anwenden… Dein Hinweis hat mich leider nicht weitergebracht… Ich versuche es aber nachzuvollziehen und sende das Ergebnis in den Thread…

:upside_down_face: Das weiß ich zum Glück… da Java Script offensichtlich wesentlich schneller ausgeführt wird und eigentlich “einfacher” ist, wenn man erstmal reingekommen ist, will ich alle alten und zukünftigen Intelligenten Regeln in Java Script (um-) schreiben…

Mit Hilfe deines Vorschlags funktioniert das Ganze für die Hauptgruppe und die Untergruppen in der ersten Ebene wie folgt:

function performsmartrule(records){ 
let app = Application("DEVONthink 3");
records.forEach(r => {
	r.date = new Date();
	gruppen = r.children.whose({ _match: [ObjectSpecifier().type, "group"] })();
		gruppen.forEach(g => {
		g.date = new Date();
		})
	})
}

Wie könnte man das auf alle weiteren Ebenen von Untergruppen anwenden?

Danke im Voraus… :egg: :rabbit2:

Da wäre ich mit nicht so sicher. Der Engpass dürfte noch die Sprache sein, sondern die Apple Events darunter. Will sagen: die zugrundeliegende Architektur ist mE wichtiger als die Sprache selbst (was die Performance angeht).

Mein Code sollte illustrieren, wie du aus einer Menge von Datensätzen nur die Gruppen raussuchst.

Das kannst du natürlich auch rekursiv erledigen, also zB

function datumSetzen(records) {
gruppen = records.whose({ _match: [ObjectSpecifier().type, "group"] })();
gruppen.forEach(g => {
  g.creationDate =...
  datumSetzen(g.children);
})

Es scheint bei der Ausführung von intelligenten Regeln einige Besonderheiten zu geben, die ich noch lernen muss… Da ich nur zwei Ebenen von Untergruppen habe, ist das folgende Skript aktuell für mich ausreichend:

function performsmartrule(records){ 
let app = Application("DEVONthink 3");
records.forEach(r => {
	r.date = new Date(); // 1.
	gruppen = r.children.whose({ _match: [ObjectSpecifier().type, "group"] })();
		gruppen.forEach(g => {
		g.date = new Date(); // 1.
			untergruppen = g.children.whose({ _match: [ObjectSpecifier().type, "group"] })();
			untergruppen.forEach(u1 => {
			u1.date = new Date(); // 1.
			})
		})
	})
}

Danke nochmals herzlich für die Hilfe!

Eigentlich nicht (außer, dass u.U. irgendwas nicht so funktioniert, wie es sollte. Was in der Vergangenheit immer beim nächsten DT-Update behoben war). JavaScript in intelligenten Regeln funktioniert genau so wie jedes JXA in jeder anderen App (und außerhalb von Apps).

Ich erlaube mir einige Bemerkungen zu deinem Script. Die sind nicht als Kritik gemeint, sondern nur als Hinweise.

let app=: Grundsätzlich sollte man nur das mit let deklarieren, was wirklich veränderbar sein muss. Alles andere mit const, denn das verhindert ungewollte Änderungen. Ich weiß, dass das let schon in dem Gerüst steht, das DT für JavaScript in intelligenten Regeln vorgibt. Das macht es aber nicht richtiger :wink:

gruppen=: Grundsätzlich sollte man alles deklarieren. Wenn man das, wie hier, nicht tut, entstehen automatisch globale Variablen, die jederzeit und überall verändert werden können. Auch (und vor allem) ungewollt. Deshalb besser const gruppen=.

Mehr dazu hier: Feld "Erstellt am" per Script füllen - #24 by chrillek

r.date = new Date() … g.date = new Date() … u1.date = new Date(): Daran ist zwar nix falsch, aber es ist auch nicht sinnvoll. Die drei generierten Daten dürften sich jeweils nur um Millisekunden unterscheiden, und diese Genauigkeit brauchst Du vermutlich gar nicht. Besser wäre etwas wie
const jetzt = new Date() … r.date = jetzt … g.date = jetzt … u1.date = jetzt

Schließlich brauchst du app nirgendwo in deinem Code, deshalb solltest Du es auch nicht deklarieren.

Das wird dich beißen, wenn es tatsächlich mal mehr als zwei Ebenen gibt. Wenn Du von Anfang an eine rekursive Funktion benutzt (wie oben beschrieben), wird zum einen der Code übersichtlicher und zum anderen bist Du für die Zukunft gerüstet.

Und: Wenn Du sinnvolle Kommentare schreibst, verstehst Du auch übermorgen noch, was Du da warum programmiert hast.