Clean up your Pasteboard! [UPDATE]
March 14, 2017 | Snippets | en | fr
UPDATE (14-Mar-2017). — Added the option “Preserve threaded text frames” as suggested by Colin Flashman and Tim Gouder. Turn it on to make sure CleanupPasteboard will not remove any text frame which belongs to a story thread.
Here is a cool script suggested by Rasmus Olsen a few days ago in the InDesign Scripting Forum. The basic purpose is to clear out the temporary components left out of the document bounds. The area to clean up can be extended or restricted via the user interface (see the animation below).
Since the main operation to perform is simple beyond expectations, let's inspect closely the side issues and the underlying objects.
Pasteboard and Spread
WARNING (15-Mar-2017). — This section was relevant in CS3/CS4—at time the original article was released (2009.) Many things have changed from then. In particular, it is no longer true that the parent of a top level PageItem is either a Page or a Spread. Today the Spread object is always the parent of any top level component, whatever its position in the layout, either inside or outside of the page area. So the following lines remains here for historical purpose only.
The most important thing you need to know about the pasteboard abstraction is that, in fact, the InDesign JavaScript DOM doesn't have any Pasteboard object. A document page-item always resides on a Spread
, even when its center point oversteps the visible bounds. The Application
and the Document
objects have a pasteboardPreferences
property, which links to a PasteboardPreference
object. In it, you will find the minimumSpaceAboveAndBelow
property — storing the “minimum space above and below a page”— and some incidental settings. Interestingly, the InDesign SDK API provides a IPasteboard
class (‘I’ for ‘Interface’) used to “access the geometry of the document's pasteboard.” The pasteboard is in no way a container, it only provides the base of the coordinate system (Pasteboard coordinate space), as illustrated in the SDK Programming Guide:
Thus, when we talk about cleaning up the pasteboard, the actual area we refer to is the outer space of the pages. We access this space from the corresponding spread. A Spread
object can be seen as a set of one or more adjacent pages. It is also a ‘meta-container’, indexing all objects placed within or out of the page bounds. In other words, the spread is responsible for the page-items which are not visible from a page, the ones the user experiences as the ‘pasteboard items.’ The key fact is that a spread sees both the inner page objects and the outer ones. Suppose you've created a single Rectangle
on the active page. Now, duplicate it out of the page and read the meter: mySpread.pageItems.length
says 2, while myPage.pageItems.length
keeps to 1.
From this point, the question is: How to get exclusively the ‘pasteboard items’? The answer comes from the object hierarchy. Considering a top-level page-item —say myPageItem
— relying out of any page, the myPageItem.parent
property will refer to the Spread
—or MasterSpread
— container. So if you need to retrieve the pasteboard items of the active document, use something like this:
// Retrieving spread items in CS4 // (Works no longer in CS6 and later.) var pasteboardItems = [], pItems = app.activeDocument.pageItems.everyItem().getElements(), i,p; while( i=pItems.pop() ) { p = i.parent.constructor; if ( p == Spread || p == MasterSpread ) { pasteboardItems.push(i); } } alert(pasteboardItems.length + " object(s) are on the pasteboard");
Working with ‘Bounds’ and Units
The CleanupPasteboard script has been extended to slug, bleed and “custom offset” areas. A custom offset allows the user to set a “thinking distance” around the page bounds. As a result, we cannot re-use the pasteboard-items approach as it. We must deal with object and page bounds, measurement units and measurementEditboxes
.
Although a Spread
object is considered as the geometric union of one or several page(s), the native DOM provides no bounds
property at this level. If you want to get this functionality in your own scripts, it's easy to prototype a surrogate method based on the page bounds:
Spread.prototype.bounds = MasterSpread.prototype.bounds = function() { // return the [top,left,bottom,right] bounds of this spread var bFirst = this.pages.item(0).bounds; // bounds of the first page var bLast = this.pages.item(-1).bounds; // bounds of the last page return [ bFirst[0], bFirst[1], bLast[2], bLast[3] ]; } // sample usage alert( app.activeWindow.activeSpread.bounds() );
Our script builds a similar function —see extraBounds
inside the Document.prototype.cleanout
method,— except that the offset parameter is injected during the calculation.
Another important scripting aspect is that the bounds
property always returns the top/bottom values in the current vertical measurement units, and the left/right values in the current horizontal measurement units, depending on the UI context. (At the page-item level, geometricBounds
/visibleBounds
properties work in the same way.) However, the MeasurementEditbox
/MeasurementCombobox
controls have a specific behavior: they display the field datas (editContents
) in the custom measurement unit specified by the editUnits
property, but they interpret the value (editValue
) in points. Because of localization and type conversion issues, parsing the editContents
string by your own means may be unsafe. So, it is often better to deal with editValue
, subject to reconvert the value from points to the required measurement units.
Here is a generic approach using the UnitValue
core Javascript class:
var UNITS = (function() { var r={}, mu=MeasurementUnits; r[mu.AGATES]='agt'; r[mu.CENTIMETERS]='cm'; r[mu.CICEROS]='ci'; r[mu.INCHES]='in'; r[mu.INCHES_DECIMAL]='in'; r[mu.MILLIMETERS]='mm'; r[mu.PICAS]='pc'; r[mu.POINTS]='pt'; return(r); })(); // convert myPointsValue from pts to myMeasurementUnits var uv = UnitValue(myPointsValue, 'pt'); var convertedValue = uv.as(UNITS[myMeasurementUnits]);
The CleanupPasteboard script demonstrates this mechanism in the ViewPreference.prototype.toOffsets()
method.
CleanupPasteboard Demo
Comments
Bonjour et merci pour ce script.
Je suis toujours sous CS3, est-il possible d'adapter ce sript ?
Merci
Bonjour edfred,
Pour faire tourner le script sous CS3, je pense qu'il suffit de remplacer les deux dernières lignes:
app.doScript('app.main();', ScriptLanguage.javascript,
undefined, UndoModes.entireScript, app.activeScript.displayName);
par:
app.main();
Dites-moi si ça marche. (Avec cette modif, vous perdez seulement la faculté d'annuler globalement l'action effectuée par le script.)
Marc
Bonsoir Marc, merci pour la modification, ça fonctionne parfaitement.
Bonne fin de semaine et bon W-E.
[MàJ] La version 1.10 du script est désormais rétrocompatible avec ID CS3; et l'interface commute en langue française chez les utilisateurs francophones.
Que demander de plus, merci Marc. ;)
Bonjour Marc,
Je me joins à Edfred pour te remercier de cette MàJ, en particulier pour l'interface française.
Merci à tous deux. C'est en forgeant qu'on devient forgeron.
@+
Marc
Bonjour Marc,
Bath…
Salut Marc, il semblerait que le script ne fonctionne pas avec ma version de CS4!!? Seul les blocs à gauche des pages sont supprimés..??! Les valeurs négatives ne sont pas supportées non plus. J'ai essayé avec les pages en vis-à-vis (et sans vis-à-vis aussi). J'ai également essayé avec des blocs vides, des blocs couleurs... avec des photos dans les blocs(ça plante).
Je suis sous OS 10.4.11 et Indesign 6.04
Merci pour tout tes autres scripts plus utiles les uns que les autres ;
++
Steph
Merci, Steph, pour ton feedback. Je te contacte par email, on va essayer de voir d'où ça vient.
@+
Marc
[MàJ] La version 1.11 de CleanupPasteboard corrige le bug signalé par Steph (v. ci-dessus). Le script original ne prenait pas en considération les préférences d'origine (Origine par page vs Origine par planche). Et comme beaucoup d'utilisateurs optent pour l'origine par planche, ce bug était passé inaperçu jusqu'alors.
Au passage, petit correctif d'interface pour les utilisateurs Mac francophones qui obtenaient des caractères accentués erratiques.
Pensez à télécharger la version mise à jour!
Hi Marc,
Thank you for this script. Would it be difficult to batch a folder or all opened documents at once?
Thanks again
Hi eugen_v
> Would it be difficult to batch a folder
> or all opened documents at once?
No, it really wouldn't, especially with the “all opened documents” scope.
In the Application.prototype.main function, you mainly just need to transform:
var doc = this.activeDocument;
to a LOOP within the `this.documents` collection. Something like this:
var doc, offsets;
for( var i=this.documents.length-1 ; i>=0 ; i--)
{
doc = this.documents[i];
offsets = ( ui.choice > 1 ) ?
doc.viewPreferences.toOffsets(ui.customOffset) :
doc.documentPreferences.bsOffsets(ui.choice);
// cleanup
doc.cleanOut(offsets, ui.parseMaster);
}
Très bon!
Fantastic.
The in-depth explanation is illuminating!
Bonjour,
Est-il possible de changé la couleur du "fond perdu" avec avec javascript? et quelle est la commande? Merci.