├── 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 | 
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 | 
6 |
7 |
8 |
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
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
--------------------------------------------------------------------------------