├── .agignore ├── .github └── workflows │ └── main.yml ├── .gitignore ├── LICENSE ├── README.md ├── feature-file.txt ├── plugins ├── sQuery.areGroups.js ├── sQuery.areShapes.js ├── sQuery.move.js └── sQuery.sendToRoot.js ├── sQuery.js ├── sQuery.methods.md └── test ├── sQueryTests.js └── sTrue.js /.agignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .git/ 3 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: Run a one-line script 13 | run: echo Hello, world! 14 | - name: Run a multi-line script 15 | run: | 16 | echo Add other actions to build, 17 | echo test, and deploy your project. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Francis 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 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > Archived :\* 2 | 3 | # sQuery 4 | 5 | A growing small library of chain methods "in a jQuery way" for Sketch to make the selection and filter task a little easiest :) 6 | 7 | # Install 8 | 9 | Copy sQuery.js inside your sketch plugin bundle. 10 | Then just import them into your scripts. 11 | 12 | ```javascript 13 | // Import sQuery 14 | @import 'sQuery.js'; 15 | 16 | // Your code here 17 | ``` 18 | 19 | # Some (silly) examples 20 | 21 | ```javascript 22 | /* Hide all layers and groups */ 23 | $("*").hide(); 24 | ``` 25 | 26 | ```javascript 27 | /* Hide all text layers with less than 10% opacity */ 28 | $("%textLayers%") 29 | .filter(function () { 30 | return $(this).opacity() < 0.1; 31 | }) 32 | .hide(); 33 | ``` 34 | 35 | ```javascript 36 | /* Loop through each group and rename it with and "index" */ 37 | $("%groups%").each(function (idx) { 38 | $(this).rename("I'm group number " + idx); 39 | }); 40 | ``` 41 | 42 | ```javascript 43 | /* Remove all empty groups */ 44 | $("%groups%").isEmpty().remove(); 45 | ``` 46 | 47 | ```javascript 48 | /* Rename all bitmaps layers */ 49 | $("%images%").rename("Hi! I'm a bitmaps layer"); 50 | ``` 51 | 52 | # Write plugins 53 | 54 | ```javascript 55 | /* Example of groups filter plugin */ 56 | $.fn.areGroups = function () { 57 | this.layers = this.layers 58 | .slice() 59 | .filter((layer) => layer.class() == MSLayerGroup); 60 | return this; 61 | }; 62 | ``` 63 | 64 | # Plugins 65 | 66 | ```javascript 67 | /* Rename groups from selection */ 68 | $("%selected%").areGroups().rename("I'm a group"); 69 | 70 | /* re-Select in Sketch just the shape layers from sketch selection */ 71 | $("%selected%").areShapes().UISelect(); 72 | 73 | /* Move selected layers by 20 units in x at fixed pixel coords */ 74 | $("%selected%").move({ x: 20, y: 0 }, true); 75 | ``` 76 | 77 | # Method list 78 | 79 | - sLayers : -> sQuery 80 | - texts : -> sQuery 81 | - groups : -> sQuery 82 | - pages : -> sQuery 83 | - artboards : -> sQuery 84 | - shapes : -> sQuery 85 | - images : -> sQuery 86 | - isLocked : -> sQuery 87 | - startsWith : string -> sQuery 88 | - endsWith : string -> sQuery 89 | - contains : string -> sQuery 90 | - withName : string -> sQuery 91 | - childs : -> sQuery 92 | - hasClickThrought : -> sQuery 93 | - setHasClickThrough : bool [false] -> sQuery 94 | - toggleClickThrought : -> sQuery 95 | - isEmpty : -> sQuery 96 | - isVisible : -> sQuery 97 | - isHidden : -> sQuery 98 | - visibility : bool -> sQuery 99 | - show : -> sQuery 100 | - hide : -> sQuery 101 | - lock : -> sQuery 102 | - unlock : -> sQuery 103 | - duplicate : string -> sQuery 104 | - remove : -> sQuery 105 | - opacity : float -> sQuery 106 | - absolutePosition : -> sQuery 107 | - relativePosition : -> sQuery 108 | - rename : string -> sQuery 109 | - UISelect : -> sQuery 110 | - each : function -> sQuery 111 | - filter : function -> sQuery 112 | - group : string -> sQuery 113 | - createShapeLayer : string -> number -> number -> number -> number -> mslayer 114 | - createArtboard : string -> number -> number -> number -> number -> artboard 115 | -------------------------------------------------------------------------------- /feature-file.txt: -------------------------------------------------------------------------------- 1 | feature 2 | -------------------------------------------------------------------------------- /plugins/sQuery.areGroups.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sQuery plugin - areGroups 1.0 3 | * Francis Vega 4 | * 5 | * @desc Filter elements and return just LayerGroups 6 | * @return {sQuery} 7 | * @example 8 | * $('%selected%').areGroups().UISelect(); 9 | * @desc Filter the selection (in Sketchapp UI) and make a selection only with groups. 10 | */ 11 | 12 | (function($){ 13 | 14 | $.fn.areGroups = function() { 15 | this.layers = this.layers.slice().filter(layer => layer.class() == MSLayerGroup); 16 | return this; 17 | } 18 | 19 | }(sQuery)); 20 | -------------------------------------------------------------------------------- /plugins/sQuery.areShapes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sQuery plugin - areShapes 1.0 3 | * Francis Vega 4 | * 5 | * @desc Filter elements and return just ShapeGroups 6 | * @return {sQuery} 7 | * @example 8 | * $('%selected%').areShapes().UISelect(); 9 | * @desc Filter the selection (in Sketchapp UI) and make a selection only 10 | * with shape layers. 11 | */ 12 | 13 | (function($){ 14 | 15 | $.fn.areShapes = function() { 16 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup); 17 | return this; 18 | } 19 | 20 | }(sQuery)); 21 | -------------------------------------------------------------------------------- /plugins/sQuery.move.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * sQuery plugin - move 1.0 4 | * Francis Vega 5 | * 6 | * @desc Move query layers 7 | * @param {object} coords 8 | * @param {object} coords.x Position x value 9 | * @param {object} coords.y Position y value 10 | * @return {sQuery} 11 | * @example 12 | * $('%selected%').move({"x":100, "y":234}) 13 | * @desc Move "selected" layers by x100, y234 14 | */ 15 | 16 | (function($){ 17 | $.fn.move = function(coords, pixelFit = false) { 18 | 19 | let finalX, finalY; 20 | 21 | this.each(function() { 22 | 23 | if(pixelFit) { 24 | finalX = Math.round( this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x ); 25 | finalY = Math.round( this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y ); 26 | } else { 27 | finalX = this.absoluteRect().x() - this.parentRootForAbsoluteRect().rect().origin.x + coords.x; 28 | finalY = this.absoluteRect().y() - this.parentRootForAbsoluteRect().rect().origin.y + coords.y; 29 | } 30 | 31 | this.absoluteRect().x = finalX + this.parentRootForAbsoluteRect().rect().origin.x 32 | this.absoluteRect().y = finalY + this.parentRootForAbsoluteRect().rect().origin.y 33 | 34 | }); 35 | 36 | return this; 37 | 38 | } 39 | }(sQuery)); 40 | -------------------------------------------------------------------------------- /plugins/sQuery.sendToRoot.js: -------------------------------------------------------------------------------- 1 | /** 2 | * sQuery plugin - sendToRoot 1.0 3 | * Francis Vega 4 | * 5 | * @desc Send layers "back" to Artboard 6 | * @return {sQuery} 7 | * @example 8 | * $('%selected%').sendToRoot(); 9 | */ 10 | 11 | (function($) { 12 | $.fn.sendToRoot = function() { 13 | // For each query 14 | this.each(function() { 15 | const parent = this.parentGroup(); 16 | if (parent.class() != MSArtboardGroup) { 17 | // Get the artboard 18 | const artboard = this.parentRootForAbsoluteRect(); 19 | // Get this absolute position 20 | const x = this.absoluteRect().x() - artboard.absoluteRect().x(); 21 | const y = this.absoluteRect().y() - artboard.absoluteRect().y(); 22 | // Parent to it 23 | artboard.addLayers([this]); 24 | // Remove from previous parent 25 | parent.removeLayer(this); 26 | // Position new this 27 | this.frame().setX(x); 28 | this.frame().setY(y); 29 | } 30 | }); 31 | return this; 32 | } 33 | }(sQuery)); 34 | -------------------------------------------------------------------------------- /sQuery.js: -------------------------------------------------------------------------------- 1 | /* 2 | The MIT License (MIT) 3 | Copyright (c) 2017 Francis Vega 4 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 5 | associated documentation files (the "Software"), to deal in the Software without restriction, 6 | including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this 11 | permission notice shall be included in all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT 14 | NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | */ 19 | 20 | /* 21 | * 22 | * sQuery 0.1 23 | * 24 | */ 25 | 26 | let sQuery, $; 27 | 28 | (function(){ 29 | 30 | sQuery = $ = (selector, page, artboard) => new SQUERY(selector, page, artboard) 31 | 32 | /** 33 | * findObjectsByName 34 | * @param {string} name The name of the object (layer) 35 | * @param {scope} scope The scope (layers) of search 36 | * @return {MSArray} 37 | */ 38 | const findObjectsByName = (name, scope) => { 39 | const predicate = NSPredicate.predicateWithFormat("name == %@", name) 40 | return scope.filteredArrayUsingPredicate(predicate) 41 | } 42 | 43 | /** 44 | * findObjectsOfType 45 | * @param {string|classType} classType The name of the class type 46 | * @param {scope} scope The scope (layers) of search 47 | * @return {MSArray} 48 | */ 49 | const findObjectsOfType = (classType, scope) => scope.slice().filter(lyr => lyr.class() == classType) 50 | 51 | /** 52 | * flattenArray 53 | * @param {array} arr The array to flatten 54 | * @return {array} return a one level deep array 55 | */ 56 | const flattenArray = arr => arr.reduce( (flat, toFlatten) => 57 | flat.concat( Array.isArray(toFlatten) ? flattenArray(toFlatten) : toFlatten), [] 58 | ) 59 | 60 | const SQUERY = function(selector, page, artboard) { 61 | 62 | if (typeof selector == "string") { 63 | 64 | // Consts 65 | const DOC = context.document; 66 | const CURRENTPAGE = DOC.currentPage(); 67 | const CURRENTARTBOARD = CURRENTPAGE.currentArtboard(); 68 | 69 | switch(selector) { 70 | // All 71 | case "*": 72 | this.layers = CURRENTARTBOARD.children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape") 73 | break 74 | 75 | case "%hierarchy%": 76 | this.layers = CURRENTARTBOARD.layers() 77 | break 78 | 79 | case "%pages%": 80 | this.layers = DOC.pages() 81 | break 82 | 83 | case "%artboards%": 84 | this.layers = CURRENTPAGE.artboards() 85 | break 86 | 87 | case "%images%": 88 | this.layers = findObjectsOfType(MSBitmapLayer, CURRENTARTBOARD.children()) 89 | break 90 | 91 | case "%layers%": 92 | this.layers = CURRENTARTBOARD.children().slice().filter(layer => layer.class() != "MSArtboardGroup" && layer.class() != "MSRectangleShape" && layer.class() != "MSLayerGroup") 93 | break 94 | 95 | case "%shapes%": 96 | this.layers = findObjectsOfType(MSShapeGroup, CURRENTARTBOARD.children()) 97 | break 98 | 99 | case "%groups%": 100 | this.layers = findObjectsOfType(MSLayerGroup, CURRENTARTBOARD.children()) 101 | break 102 | 103 | case "%textLayers%": 104 | this.layers = findObjectsOfType(MSTextLayer, CURRENTARTBOARD.children()) 105 | break 106 | 107 | case "%selected%": 108 | this.layers = context.selection 109 | break 110 | 111 | // Default: Layer name. 112 | default: 113 | this.layers = findObjectsByName(selector, CURRENTARTBOARD.children()) 114 | break 115 | } 116 | } 117 | 118 | if (typeof selector == "object") { 119 | this.layers = [selector] 120 | } 121 | 122 | return this 123 | } 124 | 125 | /* @sQuery API */ 126 | 127 | sQuery.fn = SQUERY.prototype = { 128 | 129 | /** 130 | * Return an array with the queried layers 131 | * @return {array} 132 | */ 133 | sLayers: function() { 134 | return this.layers 135 | }, 136 | 137 | /** 138 | * Query text layers 139 | * @return {sQuery} 140 | */ 141 | texts: function() { 142 | this.layers = this.layers.slice().filter(layer => layer.class() == MSTextLayer) 143 | return this 144 | }, 145 | 146 | /** 147 | * Query groups 148 | * @return {sQuery} 149 | */ 150 | groups: function() { 151 | this.layers = this.layers.slice().filter(layer => layer.class() == MSLayerGroup) 152 | return this 153 | }, 154 | 155 | /** 156 | * Query pages 157 | * @return {sQuery} 158 | */ 159 | pages: function() { 160 | this.layers = this.layers.slice().filter(layer => layer.class() == MSPage) 161 | return this 162 | }, 163 | 164 | /** 165 | * Query artboards 166 | * @return {sQuery} 167 | */ 168 | artboards: function() { 169 | this.layers = this.layers.slice().filter(layer => layer.class() == MSArtboardGroup) 170 | return this 171 | }, 172 | 173 | /** 174 | * Query shape layers 175 | * @return {sQuery} 176 | */ 177 | shapes: function() { 178 | this.layers = this.layers.slice().filter(layer => layer.class() == MSShapeGroup) 179 | return this 180 | }, 181 | 182 | /** 183 | * images 184 | * @return {sQuery} 185 | */ 186 | images: function() { 187 | this.layers = this.layers.slice().filter(layer => layer.class() == MSBitmapLayer) 188 | return this 189 | }, 190 | 191 | /** 192 | * isLocked 193 | * @return {sQuery} 194 | */ 195 | isLocked: function() { 196 | this.layers = this.layers.slice().filter(layer => layer.isLocked()) 197 | return this 198 | }, 199 | 200 | /** 201 | * startsWith 202 | * @param {string} str 203 | * @return {sQuery} 204 | */ 205 | startsWith: function(str) { 206 | this.layers = this.layers.slice().filter(layer => layer.name().substr(0, str.length) == str) 207 | return this 208 | }, 209 | 210 | /** 211 | * endsWith 212 | * @param {string} str 213 | * @return {sQuery} 214 | */ 215 | endsWith: function(str) { 216 | this.layers = this.layers.slice().filter(layer => layer.name().substr(layer.name().length() - str.length) == str) 217 | return this 218 | }, 219 | 220 | /** 221 | * contains 222 | * @param {string} str 223 | * @return {sQuery} 224 | */ 225 | contains: function(str) { 226 | this.layers = this.layers.slice().filter(layer => layer.name().indexOf(str) != -1) 227 | return this 228 | }, 229 | 230 | /** 231 | * withName 232 | * @param {string} name 233 | * @return {sQuery} 234 | */ 235 | withName: function(name) { 236 | this.layers = this.layers.slice().filter(layer => layer.name() == name) 237 | return this 238 | }, 239 | 240 | /** 241 | * childs 242 | * @return {sQuery} 243 | */ 244 | childs: function() { 245 | this.layers = flattenArray( 246 | this.layers.slice().map(function(layer) { 247 | if (layer.class() == MSSymbolInstance) { 248 | const symbolMasterId = layer.symbolMaster().objectID() 249 | const symbolChilds = layer.symbolMaster().children().slice() 250 | const symbolChildsWithoutSymbolItself = symbolChilds.filter(symbolChildsLayer => symbolChildsLayer.objectID() != symbolMasterId) 251 | return symbolChildsWithoutSymbolItself 252 | } else { 253 | return layer.children().slice() 254 | } 255 | }) 256 | ) 257 | return this 258 | }, 259 | 260 | /** 261 | * hasClickThrought 262 | * @return {sQuery} 263 | */ 264 | hasClickThrought: function() { 265 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup) 266 | this.layers = groups.filter(layer => layer.hasClickThrough()) 267 | return this 268 | }, 269 | 270 | /** 271 | * setHasClickThrough 272 | * @return {sQuery} 273 | */ 274 | setHasClickThrough: function(status = false) { 275 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup) 276 | groups.map(layer => layer.setHasClickThrough(status)) 277 | return this 278 | }, 279 | 280 | /** 281 | * toggleClickThrought 282 | * @return {sQuery} 283 | */ 284 | toggleClickThrought: function() { 285 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup) 286 | groups.map(layer => layer.setHasClickThrough(!layer.hasClickThrough())) 287 | return this 288 | }, 289 | 290 | /** 291 | * isEmpty 292 | * @return {sQuery} 293 | */ 294 | isEmpty: function() { 295 | const groups = this.layers.slice().filter(layer => layer.class() == MSLayerGroup) 296 | this.layers = groups.filter(layer => layer.layers().length === 0) 297 | return this 298 | }, 299 | 300 | /** 301 | * isVisible 302 | * @return {sQuery} 303 | */ 304 | isVisible: function() { 305 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 1) 306 | return this 307 | }, 308 | 309 | /** 310 | * isHidden 311 | * @return {sQuery} 312 | */ 313 | isHidden: function() { 314 | this.layers = this.layers.slice().filter(layer => layer.isVisible() == 0) 315 | return this 316 | }, 317 | 318 | /** 319 | * visibility 320 | * @param {bool} status 321 | * @return {sQuery} 322 | */ 323 | visibility: function(status) { 324 | this.layers.slice().map(layer => layer.setIsVisible(status)) 325 | return this 326 | }, 327 | 328 | /** 329 | * show 330 | * @return {sQuery} 331 | */ 332 | show: function() { 333 | this.layers.slice().map(layer => layer.setIsVisible(true)) 334 | return this 335 | }, 336 | 337 | /** 338 | * hide 339 | * @return {sQuery} 340 | */ 341 | hide: function() { 342 | this.layers.slice().map(layer => layer.setIsVisible(false)) 343 | return this 344 | }, 345 | 346 | /** 347 | * lock 348 | * @return {sQuery} 349 | */ 350 | lock: function() { 351 | this.layers.slice().map(layer => layer.setIsLocked(true)) 352 | return this 353 | }, 354 | 355 | /** 356 | * unlock 357 | * @return {sQuery} 358 | */ 359 | unlock: function() { 360 | this.layers.slice().map(layer => layer.setIsLocked(false)) 361 | return this 362 | }, 363 | 364 | /** 365 | * duplicate 366 | * @param {string} name 367 | * @return {sQuery} 368 | */ 369 | duplicate: function(name) { 370 | const duplicateLayers = this.layers.slice().map(layer => layer.duplicate()) 371 | duplicateLayers.map(layer => layer.name = name) 372 | this.layers = duplicateLayers 373 | return this 374 | }, 375 | 376 | /** 377 | * remove 378 | * @return {sQuery} 379 | */ 380 | remove: function() { 381 | this.layers.slice().map(layer => layer.removeFromParent()) 382 | }, 383 | 384 | /** 385 | * opacity 386 | * @param {number} val 387 | * @return {sQuery} 388 | */ 389 | opacity: function(val) { 390 | if (val) { 391 | this.layers.slice().map(layer => layer.style().contextSettings().opacity = val / 100) 392 | } else { 393 | return this.layers.slice().map(layer => layer.style().contextSettings().opacity()) 394 | } 395 | }, 396 | 397 | /** 398 | * absolutePosition 399 | * @return {sQuery} 400 | */ 401 | absolutePosition: function() { 402 | return this.layers.slice().map(layer => [layer.absoluteRect().x(), layer.absoluteRect().y()]) 403 | }, 404 | 405 | /** 406 | * relativePosition 407 | * @return {sQuery} 408 | */ 409 | relativePosition: function() { 410 | return this.layers.slice().map(layer => 411 | [ 412 | layer.absoluteRect().x() - layer.parentRootForAbsoluteRect().rect().origin.x, 413 | layer.absoluteRect().y() - layer.parentRootForAbsoluteRect().rect().origin.y 414 | ] 415 | ) 416 | }, 417 | 418 | /** 419 | * rename 420 | * @param {string} name 421 | * @return {sQuery} 422 | */ 423 | rename: function(name) { 424 | this.layers.slice().map(layer => layer.name = name) 425 | return this 426 | }, 427 | 428 | /** 429 | * UISelect 430 | * @return {sQuery} 431 | */ 432 | UISelect: function() { 433 | context.selection[0].select_byExpandingSelection(0, 0) 434 | this.layers.slice().map(layer => layer.select_byExpandingSelection(true, true)) 435 | return this 436 | }, 437 | 438 | /** 439 | * Itera por cada uno de los elementos previamente seleccionados y devuelve el elemento. 440 | * @param {function} callback Una función a la que each llama por cada iteración. 441 | * @return {sQuery} 442 | */ 443 | each: function(callback) { 444 | for(let i=0, len=this.layers.length; i sQuery 3 | texts : -> sQuery 4 | groups : -> sQuery 5 | pages : -> sQuery 6 | artboards : -> sQuery 7 | shapes : -> sQuery 8 | images : -> sQuery 9 | isLocked : -> sQuery 10 | startsWith : string -> sQuery 11 | endsWith : string -> sQuery 12 | contains : string -> sQuery 13 | withName : string -> sQuery 14 | childs : -> sQuery 15 | hasClickThrought : -> sQuery 16 | setHasClickThrough : bool [false] -> sQuery 17 | toggleClickThrought : -> sQuery 18 | isEmpty : -> sQuery 19 | isVisible : -> sQuery 20 | isHidden : -> sQuery 21 | visibility : bool -> sQuery 22 | show : -> sQuery 23 | hide : -> sQuery 24 | lock : -> sQuery 25 | unlock : -> sQuery 26 | duplicate : string -> sQuery 27 | remove : -> sQuery 28 | opacity : float -> sQuery 29 | absolutePosition : -> sQuery 30 | relativePosition : -> sQuery 31 | rename : string -> sQuery 32 | UISelect : -> sQuery 33 | each : function -> sQuery 34 | filter : function -> sQuery 35 | group : string -> sQuery 36 | createShapeLayer : string -> number -> number -> number -> number -> mslayer 37 | createArtboard : string -> number -> number -> number -> number -> artboard 38 | ``` 39 | -------------------------------------------------------------------------------- /test/sQueryTests.js: -------------------------------------------------------------------------------- 1 | log("testing start") 2 | 3 | // Generals 4 | const CURRENTPAGE = context.document.currentPage() 5 | const ARTBOARDNAME = 'new-artboard' 6 | const LAYERNAME = 'new-layer' 7 | const DUPLICATELAYERNAME = 'new-duplicate-layer' 8 | const DUPLICATEGROUPNAME = 'new-duplicate-group' 9 | const GROUPNAME = 'new-group' 10 | 11 | /** 12 | * ClickThrough 13 | */ 14 | sTrue("ClickThrough", function() { 15 | 16 | // @Setup 17 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 18 | const layer = $(artboard).createShapeLayer(LAYERNAME) 19 | const newGroup = $("%shapes%").group(GROUPNAME) 20 | 21 | // @Tests 22 | $(newGroup).setHasClickThrough(true) 23 | this.isTrue(newGroup.hasClickThrough()) 24 | $(newGroup).setHasClickThrough() 25 | this.isFalse(newGroup.hasClickThrough()) 26 | 27 | // @End 28 | $(layer).remove() 29 | $(artboard).remove() 30 | 31 | }) 32 | 33 | /** 34 | * Comprueba que se pueden duplicar capas y grupos 35 | */ 36 | sTrue("Duplicar capas y grupos", function() { 37 | 38 | // @Setup 39 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 40 | const layer = $(artboard).createShapeLayer(LAYERNAME) 41 | const newGroup = $("%shapes%").group(GROUPNAME) 42 | const duplicateLayer = $(layer).duplicate(DUPLICATELAYERNAME) 43 | const duplicateGroup = $(newGroup).duplicate(DUPLICATEGROUPNAME) 44 | 45 | // @Tests 46 | this.isEqual(duplicateLayer.layers[0].name(), DUPLICATELAYERNAME) 47 | this.isEqual(duplicateGroup.layers[0].name(), DUPLICATEGROUPNAME) 48 | 49 | // @End 50 | $(layer).remove() 51 | $(artboard).remove() 52 | 53 | }) 54 | 55 | /** 56 | * Comprueba que se puede crear un artboard 57 | */ 58 | sTrue("Artboard", function() { 59 | 60 | // @Setup 61 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 62 | 63 | // @Tests 64 | this.isClass(artboard, "MSArtboardGroup") 65 | this.isEqual(artboard.name(), ARTBOARDNAME) 66 | 67 | // @End 68 | $(artboard).remove() 69 | 70 | }) 71 | 72 | 73 | /** 74 | * Comprueba que se puede crear una capa de tipo shape 75 | */ 76 | sTrue("Crear una capa tipo Shape", function() { 77 | 78 | // @Setup 79 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 80 | const newLayer = $(artboard).createShapeLayer(ARTBOARDNAME) 81 | 82 | // @Tests 83 | this.isClass(newLayer, "MSShapeGroup") 84 | 85 | // @End 86 | $(newLayer).remove() 87 | $(artboard).remove() 88 | 89 | }) 90 | 91 | /** 92 | * Comprueba que se puede borrar una capa 93 | */ 94 | sTrue("Borra una capa", function() { 95 | 96 | // @Setup 97 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 98 | const newLayer = $(artboard).createShapeLayer(ARTBOARDNAME) 99 | $(newLayer).remove() 100 | 101 | // @Tests 102 | this.isClass(newLayer, "MSShapeGroup") 103 | 104 | // @End 105 | $(artboard).remove() 106 | 107 | }) 108 | 109 | /** 110 | * Comprueba que se pueden agrupar capas 111 | */ 112 | sTrue("Agrupar capas", function() { 113 | 114 | // @Setup 115 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 116 | const layer = $(artboard).createShapeLayer(LAYERNAME) 117 | const newGroup = $("%shapes%").group(GROUPNAME) 118 | 119 | // @Tests 120 | this.isClass(newGroup, "MSLayerGroup") 121 | this.isEqual(newGroup.name(), GROUPNAME) 122 | this.isEqual(newGroup.layers().length, 1) 123 | 124 | // @End 125 | $(layer).remove() 126 | $(artboard).remove() 127 | 128 | }) 129 | 130 | /* 131 | sTrue("Title", function() { 132 | // @Setup 133 | const artboard = $(CURRENTPAGE).createArtboard(ARTBOARDNAME, 0, 0, 800, 600) 134 | const layer = $(artboard).createShapeLayer(LAYERNAME) 135 | const newGroup = $("%shapes%").group(GROUPNAME) 136 | 137 | // @Tests 138 | //this.isTrue() 139 | //this.isFalse() 140 | //this.isEqual() 141 | //this.isNotEqual() 142 | //this.isClass() 143 | 144 | // @End 145 | }) 146 | */ 147 | -------------------------------------------------------------------------------- /test/sTrue.js: -------------------------------------------------------------------------------- 1 | let sTrue; 2 | 3 | (function() { 4 | 5 | /* 6 | * Global tests messages 7 | */ 8 | const passed = "* OK *"; 9 | const failed = "*** FAILED ***"; 10 | 11 | /* 12 | * Constructor 13 | */ 14 | sTrue = function(m, t) { 15 | indent = 2; 16 | return new STRUE(m, t); 17 | } 18 | 19 | /* 20 | * sTrue 21 | */ 22 | var STRUE = function(m, t) { 23 | log(""); 24 | title = `@test: "${m}"` 25 | logg(title, indent, ""); 26 | underline(title, indent, "´"); 27 | t.call(this); 28 | } 29 | 30 | /* 31 | * log 32 | */ 33 | const logg = (msg, leftMargin, charLeftMargin) => { 34 | log(`${" ".repeat(leftMargin)}${msg}`); 35 | } 36 | 37 | /** 38 | * Underline (log) string str with c character and p prefix margin 39 | */ 40 | function underline(str, p, c) { 41 | log(`${" ".repeat(p)}${c.repeat(str.length)}`); 42 | } 43 | 44 | /** 45 | * A custom test message 46 | * @param {boolean} the result of test 47 | * @param {string} custom test message 48 | * @param {string} the restul of the test in string 49 | * @return {boolean} 50 | */ 51 | function resultMsg(i, msg, result) { 52 | logg(`{${result}} ${msg}`, indent) 53 | } 54 | 55 | sTrue.fn = STRUE.prototype = { 56 | 57 | /* 58 | *assert: { 59 | * isTrue: function(e, msg) { 60 | * var result = failed; 61 | * if (e) { result = passed; } 62 | * if (!msg) { msg = "Should be true"; } 63 | * resultMsg(e, msg, result); 64 | * } 65 | *}, 66 | */ 67 | 68 | /** 69 | * Pass the test if 'e' is true 70 | * @return {boolean} 71 | */ 72 | isTrue: function (e, msg) { 73 | let result = failed; 74 | if (e) { result = passed; } 75 | if (!msg) { msg = "Should be true"; } 76 | resultMsg(e, msg, result); 77 | }, 78 | 79 | /** 80 | * Pass the test if 'e' is false 81 | * @return {boolean} 82 | */ 83 | isFalse: function (e, msg) { 84 | let result = failed; 85 | if (!e) { result = passed; } 86 | if (!msg) { msg = "Should be false"; } 87 | resultMsg(e, msg, result); 88 | }, 89 | 90 | /** 91 | * Pass the test if 'a' is equal to 'b' 92 | * @return {boolean} 93 | */ 94 | isEqual: function (a, b, msg) { 95 | let result = failed; 96 | let e = a == b; 97 | if (e) { result = passed; } 98 | if (!msg) { msg = "Should be equal"; } 99 | resultMsg(e, msg, result); 100 | }, 101 | 102 | /** 103 | * Pass the test if 'a' is not equal to 'b' 104 | * @return {boolean} 105 | */ 106 | isNotEqual: function (a, b, msg) { 107 | let result = failed; 108 | let e = a == b; 109 | if (!e) { result = passed; } 110 | if (!msg) { msg = "Should be not equal"; } 111 | resultMsg(e, msg, result); 112 | }, 113 | 114 | /** 115 | * Pass the test if the class of 'a' is equal to 'b' 116 | * @return {boolean} 117 | */ 118 | isClass: function (a, b, msg) { 119 | let result = failed; 120 | let e = a.class() == b; 121 | if (e) { result = passed; } 122 | if (!msg) { msg = "Should be " + b; } 123 | resultMsg(e, msg, result); 124 | }, 125 | 126 | /** 127 | * Pass the test if the type of 'a' is equal to 'b' 128 | * @return {boolean} 129 | */ 130 | isTypeof: function (a, b, msg) { 131 | let result = failed; 132 | let e = typeof(a) === b; 133 | if (e) { result = passed; } 134 | if (!msg) { msg = "Should be typeof: " + b; } 135 | resultMsg(e, msg, result); 136 | } 137 | 138 | }; 139 | 140 | }()); 141 | --------------------------------------------------------------------------------