├── LICENSE.md ├── README.md ├── Symbol Instance Locator.sketchplugin └── Contents │ ├── Resources │ └── icon.png │ └── Sketch │ ├── manifest.json │ └── script.js ├── appcast.xml └── images ├── logo.png └── screenshot.png /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jason Burns (Sonburn) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![Symbol Instance Locator](https://raw.githubusercontent.com/sonburn/symbol-instance-locator/master/images/logo.png) 2 | 3 | Locate all instances of a selected symbol or instance. Select an instance in the list of results to jump to it's location. 4 | 5 | ![Symbol Instance Locator](https://raw.githubusercontent.com/sonburn/symbol-instance-locator/master/images/screenshot.png) 6 | 7 | 8 | runner-badge-blue 9 | 10 | 11 | 12 | 13 | 14 | 15 | # Usage 16 | 17 | * cmd option shift l - Locate all instances of the selected symbol or instance 18 | 19 | # Installation 20 | 21 | ## Automatic 22 | Search for Symbol Instance Locator in [Sketchrunner](http://sketchrunner.com/) or [Sketch Toolbox](http://sketchtoolbox.com/) if you have one of those installed. 23 | 24 | Once installed, Sketch will automatically notify you when an update is available (version 0.2 and later). 25 | 26 | ## Manual 27 | 28 | 1. Download and open symbol-instance-locator-master.zip 29 | 2. Navigate to Symbol Instance Locator.sketchplugin and copy/move to your plugins directory 30 | 31 | To find your plugins directory... 32 | 33 | 1. In the Sketch menu, navigate to Plugins > Manage Plugins... 34 | 2. Click the cog in the lower left of the plugins window, and click Reveal Plugins Folder 35 | 36 | # Changelog 37 | 38 | * **1.16** - Fix for non-modified overrides appearing as overrides for instance. 39 | * **1.15** - Improvements to responsiveness, result accuracy, and better darkmode support. Fix for Sketch 72. 40 | * **1.14** - If instance master is in library, 'Go to Master' will now open the library. Override instances now show each instance and overridden layer name. 41 | * **1.13** - Fix for Sketch 53. 42 | * **1.12** - Fix for "null is not an object (evaluating 'overrides.forEach')" issue. 43 | * **1.11** - Updated method used to locate symbols used as overrides. 44 | * **1.10** - General optimizations. 45 | * **1.9** - Added plugin icon to manifest for Sketch 50. 46 | * **1.8** - Fix for plugin not working in El Capitan and updated years. 47 | * **1.7** - Fix for Sketch 48 change of currentView to contentDrawView. 48 | * **1.6** - Improved handling when selection has overrides but no instances. 49 | * **1.5** - Added support for overrides. 50 | * **1.4** - Improved handling for long symbol master names, added button to select master (if it resides in current document). 51 | * **1.3** - Added button to select all matches on current page, updated plugin screenshot. 52 | * **1.2** - Update to make the result window a floating panel, highlight for current selection, and artboard name. 53 | * **1.1** - Code optimizations and dialog frame will now be smaller if a small set of results are returned. 54 | * **1.0** - Found instances now display image of the instance, page where the instance reside, and instance name. 55 | * **0.3** - Converted list of instances to NSButtons, which when selected, will now navigate user to location of instance. 56 | * **0.2** - Added appcast plugin support for Sketch 45 and later. Significantly improved processing time, and presentation of results. 57 | * **0.1** - Initial commit. Functional, but rudimentary and will be improved upon. 58 | 59 | # Contact 60 | 61 | Find me on Twitter @sonburn 62 | 63 | # Support 64 | 65 | If you find this plugin helpful, or would like to support my plugins in general, buy me ☕️ via PayPal. 66 | 67 | # License 68 | 69 | Copyright (c) 2021 Jason Burns (Sonburn). See LICENSE.md for further details. 70 | -------------------------------------------------------------------------------- /Symbol Instance Locator.sketchplugin/Contents/Resources/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonburn/symbol-instance-locator/2dd4ef31ba2db88ffd0d961375d7fe2c6996080d/Symbol Instance Locator.sketchplugin/Contents/Resources/icon.png -------------------------------------------------------------------------------- /Symbol Instance Locator.sketchplugin/Contents/Sketch/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name" : "Symbol Instance Locator", 3 | "description" : "Locate all instances of a selected symbol or instance.", 4 | "author" : "Jason Burns", 5 | "homepage" : "https://github.com/sonburn/symbol-instance-locator", 6 | "version" : "1.16", 7 | "identifier" : "com.sonburn.sketchplugins.symbol-instance-locator", 8 | "appcast" : "https://raw.githubusercontent.com/sonburn/symbol-instance-locator/master/appcast.xml", 9 | "icon" : "icon.png", 10 | "commands" : [ 11 | { 12 | "name" : "Symbol Instance Locator", 13 | "shortcut" : "cmd option shift l", 14 | "identifier" : "locate", 15 | "description" : "Locate instances of the selected symbol or instance.", 16 | "icon" : "icon.png", 17 | "script" : "script.js", 18 | "handler" : "locate" 19 | }, 20 | { 21 | "name" : "Report Issue", 22 | "identifier" : "report", 23 | "description" : "Report an issue with Symbol Instance Locator.", 24 | "icon" : "icon.png", 25 | "script" : "script.js", 26 | "handler" : "report" 27 | }, 28 | { 29 | "name" : "Other Plugins", 30 | "identifier" : "plugins", 31 | "description" : "View all of Sonburn's plugins.", 32 | "icon" : "icon.png", 33 | "script" : "script.js", 34 | "handler" : "plugins" 35 | }, 36 | { 37 | "name" : "Donate", 38 | "identifier" : "donate", 39 | "description" : "Donate to the development of Symbol Instance Locator.", 40 | "icon" : "icon.png", 41 | "script" : "script.js", 42 | "handler" : "donate" 43 | } 44 | ], 45 | "menu" : { 46 | "title" : "Symbol Instance Locator", 47 | "items" : [ 48 | "locate", 49 | "-", 50 | "report", 51 | "plugins", 52 | "donate" 53 | ] 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Symbol Instance Locator.sketchplugin/Contents/Sketch/script.js: -------------------------------------------------------------------------------- 1 | const sketch = require('sketch') 2 | const document = sketch.getSelectedDocument() 3 | const selection = document.selectedLayers 4 | const instances = sketch.find('SymbolInstance') 5 | 6 | var pluginName = __command.pluginBundle().name() 7 | var debugMode = false 8 | 9 | var panelTitle = 16 10 | var panelHeader = 44 11 | var panelFooter = 38 12 | var panelHeight = panelTitle + panelHeader + 448 + panelFooter 13 | var panelWidth = 350 14 | var panelGutter = 15 15 | var panelItems = [] 16 | 17 | var locate = function(context) { 18 | if (selection.length != 1) { 19 | sketch.UI.alert(pluginName,'Select one symbol master or instance.') 20 | return false 21 | } 22 | 23 | var selectionType = selection.layers[0].type 24 | 25 | if (selectionType != 'SymbolMaster' && selectionType != 'SymbolInstance') { 26 | sketch.UI.alert(pluginName,'Select one symbol master or instance.') 27 | return false 28 | } 29 | 30 | var symbolMaster = (selectionType == 'SymbolMaster') ? selection.layers[0] : selection.layers[0].master 31 | var symbolMasterLibrary = symbolMaster.getLibrary() 32 | var symbolInstances = instances.filter(i => i.symbolId == symbolMaster.symbolId) 33 | var symbolOverrides = [] 34 | 35 | instances.forEach(i => { 36 | let overrides = i.overrides.filter(o => o.isDefault == false && o.editable == true && o.property == 'symbolID' && o.value == symbolMaster.symbolId) 37 | 38 | overrides.forEach(o => symbolOverrides.push({ instance : i, affectedLayer : o.affectedLayer })) 39 | }) 40 | 41 | if (!symbolInstances.length && !symbolOverrides.length) { 42 | sketch.UI.alert(pluginName,symbolMaster.name + ' has no instances or overrides.') 43 | return false 44 | } 45 | 46 | var fiber = sketch.Async.createFiber() 47 | 48 | var panel = createFloatingPanel(pluginName,NSMakeRect(0,0,panelWidth,panelHeight)) 49 | 50 | var panelClose = panel.standardWindowButton(NSWindowCloseButton) 51 | 52 | panelClose.setCOSJSTargetFunction(function() { 53 | panel.close() 54 | fiber.cleanup() 55 | }) 56 | 57 | var panelContent = createView(NSMakeRect(0,0,panelWidth,panelHeight - panelHeader)) 58 | 59 | var symbolName = createBoldDescription(symbolMaster.name,12,NSMakeRect(8,panelTitle + 8,panelWidth - 16,16)) 60 | var typeSelect = createSegmentedControl(['Instances (' + symbolInstances.length + ')','Overrides (' + symbolOverrides.length + ')'],NSMakeRect(8,panelTitle + 32,panelWidth - 16,24)) 61 | var instanceList = createScrollView(1,NSMakeRect(0,panelTitle + 64,panelWidth,384)) 62 | var selectAll = createButton('Select All on Page',NSMakeRect(0,panelTitle + 450,130,36)) 63 | var selectMaster = (symbolMasterLibrary) ? createButton('Go to Library Master',NSMakeRect(130,panelTitle + 450,144,36)) : createButton('Go to Master',NSMakeRect(130,panelTitle + 450,100,36)) 64 | 65 | let layouts = [symbolName,typeSelect,instanceList,selectAll,selectMaster] 66 | 67 | layouts.forEach(i => panelContent.addSubview(i)) 68 | 69 | selectAll.setCOSJSTargetFunction(function() { 70 | var scrolled = false 71 | 72 | deselectTargets(panelItems) 73 | 74 | document.sketchObject.currentPage().changeSelectionBySelectingLayers(nil) 75 | 76 | var symbolType = (typeSelect.indexOfSelectedItem() == 0) ? symbolInstances : symbolOverrides 77 | 78 | symbolType.forEach(function(instance,i){ 79 | var instance = (instance.affectedLayer) ? instance.instance.sketchObject : instance.sketchObject 80 | 81 | if (instance.parentPage() == document.sketchObject.currentPage()) { 82 | instance.select_byExtendingSelection(1,1) 83 | 84 | panelItems[i].setWantsLayer(1) 85 | panelItems[i].layer().setBorderWidth(2) 86 | panelItems[i].layer().setBorderColor(NSColor.controlAccentColor().CGColor()) 87 | 88 | if (scrolled == false) { 89 | instanceList.subviews().firstObject().scrollPoint(NSMakePoint(0,96 * i)) 90 | scrolled = true 91 | } 92 | } 93 | }) 94 | }) 95 | 96 | selectMaster.setCOSJSTargetFunction(function() { 97 | deselectTargets(panelItems) 98 | 99 | if (symbolMasterLibrary) { 100 | sketch.Document.open(symbolMasterLibrary.sketchObject.locationOnDisk(),(err,document) => { 101 | if (err) { 102 | sketch.UI.alert(pluginName,'There was a problem opening the library.') 103 | } 104 | 105 | let symbolMaster = document.getSymbols().find(symbol => symbol.id === symbolMaster.symbolId) 106 | 107 | document.sketchObject.documentWindow().makeKeyAndOrderFront(null) 108 | document.sketchObject.setCurrentPage(symbolMaster.sketchObject.parentPage()) 109 | document.sketchObject.contentDrawView().zoomToFitRect(symbolMaster.sketchObject.absoluteRect().rect()) 110 | 111 | symbolMaster.sketchObject.select_byExtendingSelection(1,0) 112 | }) 113 | } else { 114 | document.sketchObject.currentPage().changeSelectionBySelectingLayers(nil) 115 | document.sketchObject.setCurrentPage(symbolMaster.sketchObject.parentPage()) 116 | document.sketchObject.contentDrawView().zoomToFitRect(symbolMaster.sketchObject.absoluteRect().rect()) 117 | 118 | symbolMaster.sketchObject.select_byExtendingSelection(1,0) 119 | } 120 | }) 121 | 122 | if (!symbolOverrides.length) { 123 | displayInstances(instanceList,symbolInstances) 124 | 125 | typeSelect.setEnabled_forSegment(0,1) 126 | typeSelect.setSelected_forSegment(1,0) 127 | } else if (!symbolInstances.length) { 128 | displayInstances(instanceList,symbolOverrides) 129 | 130 | typeSelect.setEnabled_forSegment(0,0) 131 | typeSelect.setSelected_forSegment(1,1) 132 | } else { 133 | displayInstances(instanceList,symbolInstances) 134 | 135 | typeSelect.cell().setAction('callAction:') 136 | typeSelect.cell().setCOSJSTargetFunction(function(sender) { 137 | var instances = (sender.indexOfSelectedItem() == 0) ? symbolInstances : symbolOverrides 138 | 139 | displayInstances(instanceList,instances) 140 | }) 141 | } 142 | 143 | panel.contentView().addSubview(panelContent) 144 | 145 | if (!debugMode) googleAnalytics(context,'locate','run') 146 | } 147 | 148 | var report = function(context) { 149 | openUrl('https://github.com/sonburn/symbol-instance-locator/issues/new') 150 | 151 | if (!debugMode) googleAnalytics(context,'report','report') 152 | } 153 | 154 | var plugins = function(context) { 155 | openUrl('https://sonburn.github.io/') 156 | 157 | if (!debugMode) googleAnalytics(context,'plugins','plugins') 158 | } 159 | 160 | var donate = function(context) { 161 | openUrl('https://www.paypal.me/sonburn') 162 | 163 | if (!debugMode) googleAnalytics(context,'donate','donate') 164 | } 165 | 166 | function createBoldDescription(text,size,frame,alpha) { 167 | var label = NSTextField.alloc().initWithFrame(frame) 168 | 169 | label.setStringValue(text) 170 | label.setFont(NSFont.boldSystemFontOfSize(size)) 171 | label.setTextColor(NSColor.labelColor()) 172 | label.setBezeled(false) 173 | label.setDrawsBackground(false) 174 | label.setEditable(false) 175 | label.setSelectable(false) 176 | 177 | return label 178 | } 179 | 180 | function createButton(label,frame) { 181 | var button = NSButton.alloc().initWithFrame(frame) 182 | 183 | button.setTitle(label) 184 | button.setBezelStyle(NSRoundedBezelStyle) 185 | button.setAction('callAction:') 186 | 187 | return button 188 | } 189 | 190 | function createDivider(frame) { 191 | var divider = NSView.alloc().initWithFrame(frame) 192 | 193 | divider.setWantsLayer(1) 194 | divider.layer().setBackgroundColor(NSColor.separatorColor().CGColor()) 195 | 196 | return divider 197 | } 198 | 199 | function createFloatingPanel(title,frame) { 200 | var panel = NSPanel.alloc().init() 201 | 202 | panel.setTitle(title) 203 | panel.setFrame_display(frame,true) 204 | panel.setStyleMask(NSTexturedBackgroundWindowMask | NSTitledWindowMask | NSClosableWindowMask | NSFullSizeContentViewWindowMask) 205 | panel.setBackgroundColor(NSColor.windowBackgroundColor()) 206 | panel.setLevel(NSFloatingWindowLevel) 207 | panel.standardWindowButton(NSWindowMiniaturizeButton).setHidden(true) 208 | panel.standardWindowButton(NSWindowZoomButton).setHidden(true) 209 | panel.makeKeyAndOrderFront(null) 210 | panel.center() 211 | 212 | return panel 213 | } 214 | 215 | function createImage(instance,frame) { 216 | var image = NSButton.alloc().initWithFrame(frame) 217 | 218 | image.setBordered(0) 219 | image.setWantsLayer(1) 220 | image.layer().setBackgroundColor(NSColor.controlBackgroundColor()) 221 | 222 | var exportRequest = MSExportRequest.exportRequestsFromExportableLayer_inRect_useIDForName_( 223 | instance, 224 | instance.absoluteInfluenceRect(), 225 | false 226 | ).firstObject() 227 | 228 | exportRequest.format = 'png' 229 | 230 | var scaleX = (frame.size.width - 4 * 2) / exportRequest.rect().size.width 231 | var scaleY = (frame.size.height - 4 * 2) / exportRequest.rect().size.height 232 | 233 | exportRequest.scale = (scaleX < scaleY) ? scaleX : scaleY 234 | 235 | var colorSpace = NSColorSpace.sRGBColorSpace() 236 | var exporter = MSExporter.exporterForRequest_colorSpace_(exportRequest,colorSpace) 237 | var imageRep = exporter.bitmapImageRep() 238 | var instanceImage = NSImage.alloc().init().autorelease() 239 | 240 | instanceImage.addRepresentation(imageRep) 241 | 242 | image.setImage(instanceImage) 243 | 244 | return image 245 | } 246 | 247 | function createScrollView(border,frame) { 248 | var view = NSScrollView.alloc().initWithFrame(frame) 249 | 250 | view.setHasVerticalScroller(1) 251 | 252 | if (border) { 253 | view.addSubview(createDivider(NSMakeRect(0,0,frame.size.width,1))) 254 | view.addSubview(createDivider(NSMakeRect(0,frame.size.height - 1,frame.size.width,1))) 255 | } 256 | 257 | return view 258 | } 259 | 260 | function createSegmentedControl(items,frame) { 261 | var control = NSSegmentedControl.alloc().initWithFrame(frame) 262 | 263 | control.setSegmentCount(items.length) 264 | 265 | items.forEach(function(item,index) { 266 | control.setLabel_forSegment(item,index) 267 | control.setWidth_forSegment(frame.size.width / items.length - 4,index) 268 | }) 269 | 270 | control.cell().setTrackingMode(0) 271 | control.setSelected_forSegment(1,0) 272 | 273 | return control 274 | } 275 | 276 | function createTarget(instance,targets,frame) { 277 | var target = NSButton.alloc().initWithFrame(frame) 278 | 279 | target.addCursorRect_cursor(target.frame(),NSCursor.pointingHandCursor()) 280 | target.setTransparent(1) 281 | target.setAction('callAction:') 282 | target.setCOSJSTargetFunction(function(sender) { 283 | deselectTargets(panelItems) 284 | 285 | sender.setWantsLayer(1) 286 | sender.layer().setBorderWidth(2) 287 | sender.layer().setBorderColor(NSColor.controlAccentColor().CGColor()) 288 | 289 | var rect = (instance.parentArtboard()) ? instance.parentArtboard().rect() : instance.absoluteRect().rect() 290 | 291 | document.sketchObject.documentWindow().makeKeyAndOrderFront(null) 292 | document.sketchObject.setCurrentPage(instance.parentPage()) 293 | document.sketchObject.contentDrawView().zoomToFitRect(rect) 294 | 295 | instance.select_byExtendingSelection(1,0) 296 | }) 297 | 298 | targets.push(target) 299 | 300 | return target 301 | } 302 | 303 | function createTextField(string,frame) { 304 | var field = NSTextField.alloc().initWithFrame(frame) 305 | 306 | field.setStringValue(string) 307 | field.setFont(NSFont.systemFontOfSize(11)) 308 | field.setTextColor(NSColor.textColor()) 309 | field.setBezeled(0) 310 | field.setEditable(0) 311 | field.setLineBreakMode(NSLineBreakByTruncatingTail) 312 | 313 | return field 314 | } 315 | 316 | function createTextLabel(string,frame) { 317 | var field = NSTextField.alloc().initWithFrame(frame) 318 | 319 | field.setStringValue(string) 320 | field.setFont(NSFont.systemFontOfSize(9)) 321 | field.setTextColor(NSColor.labelColor()) 322 | field.setBezeled(0) 323 | field.setEditable(0) 324 | 325 | return field 326 | } 327 | 328 | function createView(frame) { 329 | var view = NSView.alloc().initWithFrame(frame) 330 | 331 | view.setFlipped(1) 332 | 333 | return view 334 | } 335 | 336 | function deselectTargets(targets) { 337 | targets.forEach(function(target){ 338 | if (target.layer()) { 339 | target.layer().setBorderWidth(0) 340 | target.setWantsLayer(0) 341 | } 342 | }) 343 | } 344 | 345 | function displayInstances(parent,instances,type) { 346 | panelItems = [] 347 | 348 | var instanceHeight = 96 349 | var instanceWidth = panelWidth - panelGutter 350 | var instanceContent = createView(NSMakeRect(0,0,instanceWidth,instanceHeight * instances.length)) 351 | var leftColWidth = 140 352 | var rightColPad = 8 353 | var rightColWidth = instanceWidth - leftColWidth - rightColPad 354 | var rightColX = rightColPad + leftColWidth 355 | var count = 0 356 | 357 | instances.forEach(function(i){ 358 | var instance = (i.instance) ? i.instance.sketchObject : i.sketchObject 359 | var listItem = createView(NSMakeRect(0,instanceHeight*count,instanceWidth,instanceHeight)) 360 | 361 | if (i.affectedLayer) { 362 | var imageArea = createImage(instance,NSMakeRect(0,0,leftColWidth,instanceHeight)) 363 | var artboardLabel = createTextLabel('Artboard',NSMakeRect(rightColX,6,rightColWidth,14)) 364 | var artboardField = createTextField((instance.parentArtboard()) ? instance.parentArtboard().name() : 'None',NSMakeRect(rightColX,18,rightColWidth,18)) 365 | var instanceLabel = createTextLabel('Instance',NSMakeRect(rightColX,34,rightColWidth,14)) 366 | var instanceField = createTextField(instance.name(),NSMakeRect(rightColX,46,rightColWidth,18)) 367 | var layerLabel = createTextLabel('Layer',NSMakeRect(rightColX,62,rightColWidth,14)) 368 | var layerField = createTextField(i.affectedLayer.name,NSMakeRect(rightColX,74,rightColWidth,18)) 369 | var targetArea = createTarget(instance,panelItems,NSMakeRect(0,0,instanceWidth,instanceHeight)) 370 | var divider = createDivider(NSMakeRect(0,instanceHeight - 1,instanceWidth,1)) 371 | 372 | let layouts = [imageArea,artboardLabel,artboardField,instanceLabel,instanceField,layerLabel,layerField,targetArea,divider] 373 | 374 | layouts.forEach(i => listItem.addSubview(i)) 375 | } else { 376 | var imageArea = createImage(instance,NSMakeRect(0,0,leftColWidth,instanceHeight)) 377 | var pageLabel = createTextLabel('Page',NSMakeRect(rightColX,6,rightColWidth,14)) 378 | var pageField = createTextField(instance.parentPage().name(),NSMakeRect(rightColX,18,rightColWidth,18)) 379 | var artboardLabel = createTextLabel('Artboard',NSMakeRect(rightColX,34,rightColWidth,14)) 380 | var artboardField = createTextField((instance.parentArtboard()) ? instance.parentArtboard().name() : 'None',NSMakeRect(rightColX,46,rightColWidth,18)) 381 | var instanceLabel = createTextLabel('Instance',NSMakeRect(rightColX,62,rightColWidth,14)) 382 | var instanceField = createTextField(instance.name(),NSMakeRect(rightColX,74,rightColWidth,18)) 383 | var targetArea = createTarget(instance,panelItems,NSMakeRect(0,0,instanceWidth,instanceHeight)) 384 | var divider = createDivider(NSMakeRect(0,instanceHeight - 1,instanceWidth,1)) 385 | 386 | let layouts = [imageArea,pageLabel,pageField,artboardLabel,artboardField,instanceLabel,instanceField,targetArea,divider] 387 | 388 | layouts.forEach(i => listItem.addSubview(i)) 389 | } 390 | 391 | instanceContent.addSubview(listItem) 392 | 393 | count++ 394 | }) 395 | 396 | parent.setDocumentView(instanceContent) 397 | } 398 | 399 | function googleAnalytics(context,category,action,label,value) { 400 | var trackingID = 'UA-118987499-1' 401 | var uuidKey = 'google.analytics.uuid' 402 | var uuid = NSUserDefaults.standardUserDefaults().objectForKey(uuidKey) 403 | 404 | if (!uuid) { 405 | uuid = NSUUID.UUID().UUIDString() 406 | NSUserDefaults.standardUserDefaults().setObject_forKey(uuid,uuidKey) 407 | } 408 | 409 | var url = 'https://www.google-analytics.com/collect?v=1' 410 | // Tracking ID 411 | url += '&tid=' + trackingID 412 | // Source 413 | url += '&ds=sketch' + sketch.version.sketch 414 | // Client ID 415 | url += '&cid=' + uuid 416 | // pageview, screenview, event, transaction, item, social, exception, timing 417 | url += '&t=event' 418 | // App Name 419 | url += '&an=' + encodeURI(context.plugin.name()) 420 | // App ID 421 | url += '&aid=' + context.plugin.identifier() 422 | // App Version 423 | url += '&av=' + context.plugin.version() 424 | // Event category 425 | url += '&ec=' + encodeURI(category) 426 | // Event action 427 | url += '&ea=' + encodeURI(action) 428 | // Event label 429 | if (label) { 430 | url += '&el=' + encodeURI(label) 431 | } 432 | // Event value 433 | if (value) { 434 | url += '&ev=' + encodeURI(value) 435 | } 436 | 437 | var session = NSURLSession.sharedSession() 438 | var task = session.dataTaskWithURL(NSURL.URLWithString(NSString.stringWithString(url))) 439 | 440 | task.resume() 441 | } 442 | 443 | function openUrl(url) { 444 | NSWorkspace.sharedWorkspace().openURL(NSURL.URLWithString(url)) 445 | } 446 | -------------------------------------------------------------------------------- /appcast.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Symbol Instance Locator 5 | http://sparkle-project.org/files/sparkletestcast.xml 6 | Locate all instances of a selected symbol or instance. 7 | en 8 | 9 | Version 1.16 10 | 11 | 13 |
  • Fix for non-modified overrides appearing as overrides for instance.
  • 14 | 15 | ]]> 16 |
    17 | 18 |
    19 |
    20 |
    21 | -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonburn/symbol-instance-locator/2dd4ef31ba2db88ffd0d961375d7fe2c6996080d/images/logo.png -------------------------------------------------------------------------------- /images/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sonburn/symbol-instance-locator/2dd4ef31ba2db88ffd0d961375d7fe2c6996080d/images/screenshot.png --------------------------------------------------------------------------------