I’m experiencing difficulty in getting the onDocumentChanged to fire.
I’ve also tried updating the action based on the actions documentation:
”OpenDocument.finish”:”onOpenDocument”,
or
”OpenDocument”:”onOpenDocument”,
in my manifest, however none of these appears to be firing whenever I open a new sketch document - regardless of whether or not I open it from the recent files or directly via finder.
v101.9 (182113)
The exact problematic code snippet (if applicable/you know what it is)
Do you build your plugin with skpm? Because if you don’t, you should remove the export keyword as it’s not natively supported by Sketch and this might cause issues with script parsing.
That said, all these actions should work as is, here’s a little demo plugin I’ve put toghether that’s subscribed to OpenDocument, CloseDocument, and onDocumentChanged:
Thanks @rodionovd I was able to figure out that OpenDocument & CloseDocument are working as expected (before I was using OpenDocument.finish, etc).
Having said that… now I’m stuck on figuring out a way to detect when a paste-layer operation has completed, e.g. when a user copy & pastes a layer in the document tree, or when they create a new one - while observing end-users I’ve noticed that sometimes this can take up to 20 seconds to complete, but my plugins function is firing before that occurs…
I’m not see many comprehensive options for detecting new layer/symbol/component creation in the action reference doc.
Oh that doesn’t sound right. Could be that the app UI is updating much slower than the internal model – which ultimately calls onDocumentChange before UI is done updating.
Would be great if you could share a sample document where this issue manifests, but I guess this going to be problematic because of NDA/privacy reasons.
As for documentation on detecting document changes, I’m afraid that Sketch Developer — Document changes is the only reference we’ve got. Is there anything not covered by this guide that you’d like to know?
Thank you @rodionovd! The pasting is happening extremely late - I’m guessing due to images being too large, or some other structural issues with how the sketch file was built.
Specifically trying to find more granular set of actions that fire upon:
Adding or deleting a layer in the page tree when operation is finished (including copy & pasting)
Modifying the name a symbol or art-board when finished
Removing layers or symbols from the canvas (if no action triggered in #1 above)
Detecting selection of a deeply nested symbol (currently if someone selects a deeply nested layer/symbol in the tree - the action handler context thinks we clicked the top-level-parent in the tree.
I’ve been using this onDocumentChanged-based approach with Artboards in the past, but it seems to work with Frames as well, albeit it’s a little more verbose:
const { GroupBehavior, fromNative } = require("sketch/dom");
function onDocumentChanged(context) {
const changes = context.actionContext;
for (var i = 0; i < changes.length; i++) {
const isRename = changes[i].type() === 1 && changes[i].propertyName() == "name";
const isGroup = changes[i].object().isKindOfClass(NSClassFromString("MSLayerGroup"));
if (isRename && isGroup) {
const group = fromNative(changes[i].object());
const oldGroupSnapshot = fromNative(changes[i].oldObject());
const isCanvasLevelFrame = (group.type === 'Artboard');
if (group.groupBehavior == GroupBehavior.Frame || group.groupBehavior == GroupBehavior.Graphic) {
console.log(`Renamed a Frame (${isCanvasLevelFrame ? 'canvas level' : 'nested'}) from <${oldGroupSnapshot.name}> to <${group.name}>`);
}
}
}
}
A bit convoluted but:
const { fromNative } = require("sketch/dom");
const { toArray } = require('util');
// in manifest.json:
// "actions": {
// "SelectionChanged.finish": "onSelectionChanged"
// }
function onSelectionChanged(context) {
const document = context.actionContext.document;
toArray(document.selectionItems().allObjects()).forEach(selectionItem => {
// Check if there's secondary aka nested selection
if (selectionItem.secondarySelection()) {
const nested = fromNative(selectionItem.secondarySelection());
const parent = fromNative(selectionItem.primarySelection());
// `nested.type` will be 'undefined' for nested SymbolInstances
if (parent.type === 'SymbolInstance' && typeof nested.type === 'undefined') {
// there might be a deep hierarchy of nested symbols selected
const nestedSelectionHierarchy = toArray(selectionItem.secondaryPath()).map(fromNative).toReversed();
console.log(`Selected <${nestedSelectionHierarchy.map(nested => nested.name).join("> in <")}> -- all nested in <${parent.name}>`);
}
}
});
}