├── _string.scpt ├── Ai Merge.jsx ├── Ai Sessions.jsx ├── Merge SVG Docs.jsx ├── IconJar to Artboards.jsx ├── Contact Sheet ├── .idea │ ├── codeStyles │ │ └── codeStyleConfig.xml │ ├── vcs.xml │ ├── encodings.xml │ ├── modules.xml │ ├── Contact Sheet.iml │ ├── misc.xml │ └── workspace.xml ├── lang.jsx ├── config.jsx ├── Progress.js ├── FileList.js ├── work.js └── backup │ └── Contact Sheet.jsx ├── find-artboards-by-name.jsx ├── copy-layer-name-to-artboard.jsx ├── Smart Layer Export.jsx ├── Artboard Labels.jsx ├── Resize All Artboards.jsx ├── polyfills.js ├── Center on Artboards.jsx ├── Progress.jsx ├── README.md ├── JSON.jsx ├── Save Open Docs.jsx ├── Group Overlapping Objects.jsx ├── Iterator.js ├── Helpers.jsx ├── bak-SVG Exporter.jsx ├── SVG Exporter.jsx ├── labels.js └── utils.jsx /_string.scpt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iconifyit/ai-scripts/HEAD/_string.scpt -------------------------------------------------------------------------------- /Ai Merge.jsx: -------------------------------------------------------------------------------- 1 | #target illustrator 2 | #include "~/github/iconify/ai-merge/Ai Merge.jsx"; -------------------------------------------------------------------------------- /Ai Sessions.jsx: -------------------------------------------------------------------------------- 1 | #target illustrator 2 | #include "~/github/iconify/ai-sessions/Ai Sessions.jsx"; -------------------------------------------------------------------------------- /Merge SVG Docs.jsx: -------------------------------------------------------------------------------- 1 | #target illustrator 2 | #include "~/github/iconify/merge-svg-docs/Merge SVG Docs.jsx"; -------------------------------------------------------------------------------- /IconJar to Artboards.jsx: -------------------------------------------------------------------------------- 1 | #target illustrator 2 | #include "~/github/iconify/iconjar-to-ai/IconJar to Artboards.jsx"; -------------------------------------------------------------------------------- /Contact Sheet/.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/Contact Sheet.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /find-artboards-by-name.jsx: -------------------------------------------------------------------------------- 1 | function find() { 2 | 3 | var doc, 4 | needle; 5 | 6 | doc = activeDocument; 7 | 8 | needle = prompt("Enter a search string", ""); 9 | 10 | doc.selection = null; 11 | 12 | try { 13 | for (var i = 0; i < doc.artboards.length; i++) { 14 | if (doc.artboards[i].name.toLowerCase().indexOf(needle) >= 0) { 15 | doc.artboards.setActiveArtboardIndex(i); 16 | doc.selectObjectsOnActiveArtboard(); 17 | } 18 | } 19 | } 20 | catch(e) {alert('Error 2 : ' + e)} 21 | } 22 | find(); 23 | -------------------------------------------------------------------------------- /copy-layer-name-to-artboard.jsx: -------------------------------------------------------------------------------- 1 | app.userInteractionLevel = UserInteractionLevel.DONTDISPLAYALERTS; 2 | 3 | var doc = activeDocument, 4 | artboard = doc.artboards[doc.artboards.getActiveArtboardIndex()]; 5 | 6 | var count = doc.artboards.length; 7 | 8 | try { 9 | if (confirm('Are you sure you want to rename all artboards?')) { 10 | for (var i = 0; i < count; i++) { 11 | 12 | doc.selection = null; 13 | 14 | doc.artboards.setActiveArtboardIndex(i); 15 | artboard = doc.artboards[ 16 | doc.artboards.getActiveArtboardIndex() 17 | ]; 18 | doc.selectObjectsOnActiveArtboard(); 19 | 20 | artboard.name = doc.selection[0].parent.name; 21 | } 22 | } 23 | } 24 | catch(e) {alert(e)} 25 | 26 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | JavaScript 23 | 24 | 25 | 26 | 27 | JavaScript 28 | 29 | 30 | 31 | 32 | 33 | 34 | 36 | 37 | 40 | -------------------------------------------------------------------------------- /Smart Layer Export.jsx: -------------------------------------------------------------------------------- 1 | // Copyright 2014 Tom Byrne 2 | 3 | var file; 4 | try{ 5 | smartExport = {}; 6 | 7 | var classpath = "SmartLayerExport"; 8 | 9 | smartExport.appId = "org.tbyrne.smartLayerExport"; 10 | 11 | if($.os.toLowerCase().indexOf("macintosh")!=-1){ 12 | smartExport.directory = decodeURI(app.path + '/Presets.localized/' + app.locale + "/" + classpath); 13 | }else{ 14 | smartExport.directory = decodeURI(app.path + '/Presets/' + app.locale + "/" + classpath); 15 | } 16 | var geo_dynamic = new Folder(smartExport.directory); 17 | var scripts = geo_dynamic.getFiles(); 18 | 19 | for(var i=0; i 0) { var doc = app.activeDocument; Utils.showProgressBar(doc.artboards.length); var interrupt = false; app.executeMenuCommand("fitall"); var count = doc.artboards.length; for (i = 0; i < count; i++) { redraw(); // The interrupt is not working yet. if (interrupt) break; doc.artboards.setActiveArtboardIndex(i); var activeAB = doc.artboards[doc.artboards.getActiveArtboardIndex()]; var right = activeAB.artboardRect[2]; var bottom = activeAB.artboardRect[3]; doc.selectObjectsOnActiveArtboard(); // If there are no visible items, update the progress bar and continue. if (selection.length == 0) { Utils.updateProgress('Artboard ' + i + ' has no visible items. Skipping.'); continue; } app.executeMenuCommand('group'); Utils.updateProgressMessage('Grouping selection'); /* Utils.updateProgressMessage( 'Selection is ' + Utils.isVisibleAndUnlocked(selection) ? 'Visible' : 'Hidden'), i + 1, doc.artboards.length ); */ for (x = 0 ; x < selection.length; x++) { try { if (! Utils.isVisibleAndUnlocked(selection)) continue; selection[x].position = [ Math.round((right - selection[x].width)/2), Math.round((bottom + selection[x].height)/2) ]; var scale = 105; try { selection[x].resize(scale, scale, true, true, true, true, scale); } catch(e) { $.writeln("RESIZE ERROR : " + e); } } catch(e) { Utils.logger('ERROR - ' + e.message); } } Utils.updateProgress('Selection centered'); } Utils.progress.close(); redraw(); } else { alert("There are no open documents"); } try { userInteractionLevel = originalInteractionLevel; } catch(ex) {/*Exit Gracefully*/} -------------------------------------------------------------------------------- /Progress.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Scott Lewis 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | var Progress = { 27 | 28 | top: 0, 29 | 30 | left: 0, 31 | 32 | width: 450, 33 | 34 | height: 100, 35 | 36 | minvalue: 0, 37 | 38 | maxvalue: 100, 39 | 40 | window: null, 41 | 42 | panel: null, 43 | 44 | init: function(start, end) { 45 | 46 | Progress.minvalue = start; 47 | Progress.maxvalue = end; 48 | 49 | var top, right, bottom, left; 50 | 51 | Progress.top = 0; 52 | Progress.left = 0; 53 | Progress.width = 450; 54 | Progress.height = 100; 55 | 56 | if ( bounds = Utils.getScreenSize() ) { 57 | left = Math.abs(Math.ceil((bounds.width/2) - (Progress.width/2))); 58 | top = Math.abs(Math.ceil((bounds.height/2) - (Progress.height/2))); 59 | } 60 | 61 | Progress.window = new Window( 62 | 'palette', 63 | 'Progress', 64 | [left, top, left + Progress.width, top + Progress.height] 65 | ); 66 | 67 | Progress.window.pnl = progress.add( 68 | 'panel', 69 | [10, 10, 440, 100], 70 | 'Progress' 71 | ); 72 | 73 | Progress.window.pnl.progBar = progress.pnl.add( 74 | 'progressbar', 75 | [20, 35, 410, 60], 76 | 0, 77 | Progress.maxvalue 78 | ); 79 | 80 | Progress.window.pnl.progBarLabel = progress.pnl.add( 81 | 'statictext', 82 | [20, 20, 320, 35], 83 | "0 of " + Progress.maxvalue 84 | ); 85 | }, 86 | 87 | show: function() { 88 | try { Progress.close(); } catch(e){}; 89 | Progress.obj.show(); 90 | }, 91 | 92 | update: function() { 93 | Progress.window.pnl.progBar.value++; 94 | var val = Progress.window.pnl.progBar.value; 95 | var max = Progress.window.pnl.progBar.maxvalue; 96 | Progress.window.pnl.progBarLabel.text = val + ' of ' + max; 97 | $.sleep(10); 98 | Progress.window.update(); 99 | }, 100 | 101 | close: function() { 102 | Progress.window.close(); 103 | } 104 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ai Scripts 2 | 3 | My collection of Ai JSX scripts I use day-to-day 4 | 5 | ## Installation 6 | 7 | Copy the contents of this folder to `Adobe Illustrator/Presets/EN_US/Scripting/` 8 | 9 | Replace `EN_US` with whatever language you are using. 10 | 11 | ## Ai Sessions 12 | 13 | This script will save a list of currently open documents to a small JSON file in your home directory. You can re-open the same collection of files any time by running the script and choesing the Session date from the list. Only the 10 most recent sessions are saved. 14 | 15 | ### Usage: 16 | 17 | 1. Navigate to `File / Scripts / Ai Sessions` 18 | 2. Click `Save` to save the current session 19 | 3. To return to a session navigate to `File / Scripts / Ai Sessions` 20 | 4. Select the desired session date from the list 21 | 22 | ## Batch Resize Artboards 23 | 24 | This script will resize all artboards in all documents in a folder (such as a folder of SVG files). 25 | 26 | ### Usage 27 | 28 | 1. Navigate to `File / Scripts / Batch Resize Artboards` 29 | 2. When prompted, select the desired folder of files to resize 30 | 3. When prompted, enter an integer value for the width/height of the new artboards. 31 | 32 | 33 | ## Contact Sheet 34 | 35 | This script creates a contact sheet from a source folder of SVG files. For more details see https://github.com/iconfinder/scripts-for-icondesigners/tree/master/icon-contact-sheet 36 | 37 | ## Merge SVG Docs 38 | 39 | This script will merge a folder of SVG files into a single document. Each SVG file will be placed on its own artboard. The artboard name will match the file name minus the file extension. 40 | 41 | Since Illustrator is currently limited to 100 artboards per file, the script can only accommodate 100 files max. If you have more than 100 files, split them into multiple folders. 42 | 43 | ### Usage 44 | 45 | 1. Navigate to `File / Scripts / Merge SVG Docs` 46 | 2. When prompted, select the desired folder of files to merge 47 | 48 | ## MoveItemsToNearestPixel 49 | 50 | This script will move all items in an illustrator file to the nearest pixel. 51 | 52 | ### Usage 53 | 54 | 1. With an open Illustrator document 55 | 2. Navigate to `File / Scripts / MoveItemsToNearestPixel` 56 | 57 | ## MultiExporter 58 | 59 | Exports all groups or layers in an Illustrator document to individual SVG or PDF files. 60 | 61 | This script is a modified version of the script by the same name by Matthew Ericson - mericson@ericson.net 62 | 63 | _Copyright 2011 Matthew Ericson_ 64 | _Comments or suggestions to mericson@ericson.net_ 65 | 66 | ## ResizeAllArtboards 67 | 68 | This script resizes all artboards in an open Ai document. 69 | 70 | ### Usage 71 | 72 | 1. Navigate to `File / Scripts / Resize All Artboards` 73 | 2. When prompted, enter an integer value for the width/height of the new artboards. 74 | 75 | ## Smart Layer Export 76 | 77 | This script exports any layers, Groups, or artboards whose name ends with `.svg` as an SVG file. 78 | 79 | This script is a modified version of the script by the same name by P. J. Onori as part of the Iconic system. 80 | For more information, please visit 81 | 82 | ## z_Adobe 83 | 84 | This is an archive folder of the default Adobe Illustrator scripts. 85 | 86 | ## z_Iconify 87 | 88 | This is an archive folder of older versions of scripts I use. -------------------------------------------------------------------------------- /Contact Sheet/lang.jsx: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * Global strings object. 4 | * @type {{ 5 | * LABEL_DIALOG_WINDOW : string, 6 | * NO_SELECTION : string, 7 | * LABEL_PG_WIDTH : int, 8 | * LABEL_PG_HEIGHT : int, 9 | * LABEL_COL_COUNT : int, 10 | * LABEL_ROW_COUNT : int, 11 | * LABEL_SCALE : number, 12 | * LABEL_FILE_NAME : string, 13 | * LABEL_LOGGING : boolean, 14 | * BUTTON_CANCEL : string, 15 | * BUTTON_OK : string, 16 | * DOES_NOT_EXIST : string, 17 | * LAYER_NOT_CREATED : string, 18 | * LABEL_SRC_FOLDER : string, 19 | * LABEL_CHOOSE_FOLDER : string, 20 | * LABEL_INPUT : string, 21 | * LABEL_SIZE : string, 22 | * LABEL_OUTPUT : string 23 | * }} 24 | */ 25 | var LANG = { 26 | /** 27 | * Dialog window label 28 | */ 29 | LABEL_DIALOG_WINDOW: "Contact Sheet Settings", 30 | 31 | /** 32 | * Confirm delete preset 33 | */ 34 | CONFIRM_DELETE_PRESET: 'Are you sure you want to delete the preset file?', 35 | 36 | /** 37 | * Choose file string 38 | */ 39 | CHOOSE_FILE: "Choose a file", 40 | 41 | /** 42 | * No selection error string. 43 | */ 44 | NO_SELECTION: "No selection", 45 | 46 | /** 47 | * Page width field label. 48 | */ 49 | LABEL_PG_WIDTH: "Page Width:", 50 | 51 | /** 52 | * Page height field label. 53 | */ 54 | LABEL_PG_HEIGHT: "Page Height:", 55 | 56 | /** 57 | * Column count field label. 58 | */ 59 | LABEL_COL_COUNT: "Column Count:", 60 | 61 | /** 62 | * Row count field label. 63 | */ 64 | LABEL_ROW_COUNT: "Row Count:", 65 | 66 | /** 67 | * Scale field label. 68 | */ 69 | LABEL_SCALE: "Scale:", 70 | 71 | /** 72 | * File name field label. 73 | */ 74 | LABEL_FILE_NAME: "File Name:", 75 | 76 | /** 77 | * Logging field label. 78 | */ 79 | LABEL_LOGGING: "Logging?", 80 | 81 | /** 82 | * Cancel button text. 83 | */ 84 | BUTTON_CANCEL: "Cancel", 85 | 86 | /** 87 | * OK button text. 88 | */ 89 | BUTTON_OK: "Ok", 90 | 91 | /** 92 | * Save button text 93 | */ 94 | BUTTON_SAVE: "Save Preset", 95 | 96 | /** 97 | * Delete button text 98 | */ 99 | BUTTON_DELETE: "Delete", 100 | 101 | /** 102 | * Object does not exist error string. 103 | */ 104 | DOES_NOT_EXIST: " does not exist", 105 | 106 | /** 107 | * Could not create document error string. 108 | */ 109 | DOC_NOT_CREATED: "The document could not be created. ", 110 | 111 | /** 112 | * Could not create layer error string. 113 | */ 114 | LAYER_NOT_CREATED: "Could not create layer. ", 115 | 116 | /** 117 | * Source folder field label. 118 | */ 119 | LABEL_SRC_FOLDER: "Source Folder", 120 | 121 | /** 122 | * Choose folder label. 123 | */ 124 | LABEL_CHOOSE_FOLDER: "Choose Folder", 125 | 126 | /** 127 | * Input field label. 128 | */ 129 | LABEL_INPUT: "Input", 130 | 131 | /** 132 | * Size field label. 133 | */ 134 | LABEL_SIZE: "Size", 135 | 136 | /** 137 | * Output field label. 138 | */ 139 | LABEL_OUTPUT: "Output", 140 | 141 | /** 142 | * Presets label 143 | */ 144 | LABEL_PRESETS: "Presets" 145 | }; -------------------------------------------------------------------------------- /Contact Sheet/config.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Global options object used to avoid having to pass a large number of variables in function calls. 3 | * @type {{ 4 | * ROWS : int, 5 | * COLS : int, 6 | * VOFF : number, 7 | * HOFF : number, 8 | * ROW_WIDTH : number, 9 | * COL_WIDTH : number, 10 | * FRM_WIDTH : number, 11 | * FRM_HEIGHT : number, 12 | * PG_WIDTH : number, 13 | * PG_HEIGHT : number, 14 | * PG_UNITS : string, 15 | * GUTTER : number, 16 | * SCALE : number, 17 | * AIFORMAT : [*], 18 | * SHRINK_TO_FIT : boolean, 19 | * START_FOLDER : string, 20 | * FILENAME : string, 21 | * LOGGING : boolean, 22 | * LOG_FILE_PATH : string, 23 | * DEBUG : boolean, 24 | * SKIP_COLS : number, 25 | * STRIP : [*] 26 | * }} 27 | */ 28 | var CONFIG = { 29 | 30 | /** 31 | * Number of rows 32 | */ 33 | 34 | ROWS: 10, 35 | 36 | /** 37 | * Number of columns 38 | */ 39 | 40 | COLS: 10, 41 | 42 | /** 43 | * Top & bottom page margins 44 | */ 45 | 46 | VOFF: 0, 47 | 48 | /** 49 | * Left & Right page margins 50 | */ 51 | 52 | HOFF: 0, 53 | 54 | /** 55 | * Row height. This is set programmatically. 56 | */ 57 | 58 | ROW_WIDTH: 64, 59 | 60 | /** 61 | * Column Height. This is set programmatically. 62 | */ 63 | 64 | COL_WIDTH: 64, 65 | 66 | /** 67 | * @deprecated 68 | */ 69 | FRM_WIDTH: 64, 70 | 71 | /** 72 | * @deprecated 73 | */ 74 | FRM_HEIGHT: 64, 75 | 76 | /** 77 | * Artboard width 78 | * 79 | * 10 columns 128 px wide, with 64 px page margins 80 | */ 81 | 82 | PG_WIDTH: 1120, 83 | 84 | /** 85 | * Artboard height 86 | * 87 | * 20 rows 128 px tall, with 64 px page margins 88 | */ 89 | 90 | PG_HEIGHT: 1400, 91 | 92 | /** 93 | * Page Count 94 | */ 95 | 96 | PG_COUNT: 1, 97 | 98 | /** 99 | * Not yet fully-implemented. Will support multiple units 100 | */ 101 | 102 | PG_UNITS: "px", 103 | 104 | /** 105 | * @deprecated 106 | */ 107 | 108 | GUTTER: 2, 109 | 110 | /** 111 | * Enter scale in percentage 1-100 112 | */ 113 | 114 | SCALE: 100, 115 | 116 | /** 117 | * Illustrator version compatibility 118 | */ 119 | 120 | AIFORMAT: Compatibility.ILLUSTRATOR10, 121 | 122 | /** 123 | * If the icon is larger than the cell size, shrink it to the cell size 124 | */ 125 | 126 | SHRINK_TO_FIT: true, 127 | 128 | /** 129 | * Starting folder for folder selector dialog 130 | */ 131 | 132 | START_FOLDER: "~/github/iconify", 133 | 134 | /** 135 | * The contact sheet file name 136 | */ 137 | 138 | FILENAME: "contact-sheet", 139 | 140 | /** 141 | * Enable logging? 142 | */ 143 | 144 | LOGGING: true, 145 | 146 | /** 147 | * Verbose logging output? 148 | */ 149 | DEBUG: true, 150 | 151 | /** 152 | * @deprecated 153 | */ 154 | 155 | SKIP_COLS: 0, 156 | 157 | /** 158 | * Not fully-implemented 159 | */ 160 | 161 | STRIP: ["svg", "ai", "eps", "txt", "pdf"], 162 | 163 | /** 164 | * Presets folder path 165 | */ 166 | PRESETS_FOLDER: '~/ai-contact-sheet/presets', 167 | 168 | /** 169 | * Log folder path 170 | */ 171 | 172 | LOG_FOLDER: '~/ai-contact-sheet/logs/', 173 | 174 | /** 175 | * Log file location 176 | */ 177 | 178 | LOG_FILE_PATH: '~/ai-contact-sheet/logs/' + Utils.doDateFormat(new Date()) + '-log.txt', 179 | 180 | /** 181 | * Default path separator 182 | */ 183 | 184 | PATH_SEPATATOR: "/" 185 | }; -------------------------------------------------------------------------------- /JSON.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Add Array.indexOf support if not supported natively. 3 | */ 4 | if(!Array.prototype.indexOf) { 5 | /** 6 | * Gets the index of an element in an array. 7 | * @param what 8 | * @param i 9 | * @returns {*} 10 | */ 11 | Array.prototype.indexOf = function(what, i) { 12 | i = i || 0; 13 | var L = this.length; 14 | while (i < L) { 15 | if(this[i] === what) return i; 16 | ++i; 17 | } 18 | return -1; 19 | }; 20 | } 21 | 22 | /** 23 | * Add Array.remove support. 24 | * @returns {Array} 25 | */ 26 | Array.prototype.remove = function() { 27 | var what, a = arguments, L = a.length, ax; 28 | while (L && this.length) { 29 | what = a[--L]; 30 | while ((ax = this.indexOf(what)) !== -1) { 31 | this.splice(ax, 1); 32 | } 33 | } 34 | return this; 35 | }; 36 | 37 | /*-------------------------------------------------------------------------------------------------------------------------*/ 38 | /** 39 | * Adds JSON library support for engines that do not include it natively. 40 | */ 41 | "object"!=typeof JSON&&(JSON={}),function(){"use strict";function f(t){return 10>t?"0"+t:t}function quote(t){ 42 | return escapable.lastIndex=0,escapable.test(t)?'"'+t.replace(escapable,function(t){var e=meta[t]; 43 | return"string"==typeof e?e:"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+t+'"'} 44 | function str(t,e){var n,r,o,f,u,i=gap,p=e[t];switch(p&&"object"==typeof p&&"function"==typeof p.toJSON&&(p=p.toJSON(t)), 45 | "function"==typeof rep&&(p=rep.call(e,t,p)),typeof p){case"string":return quote(p);case"number":return isFinite(p)?String(p):"null"; 46 | case"boolean":case"null":return String(p);case"object":if(!p)return"null";if(gap+=indent,u=[],"[object Array]"===Object.prototype.toString.apply(p)){ 47 | for(f=p.length,n=0;f>n;n+=1)u[n]=str(n,p)||"null";return o=0===u.length?"[]":gap?"[\n"+gap+u.join(",\n"+gap)+"\n"+i+"]":"["+u.join(",")+"]",gap=i,o} 48 | if(rep&&"object"==typeof rep)for(f=rep.length,n=0;f>n;n+=1)"string"==typeof rep[n]&&(r=rep[n],o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o)); 49 | else for(r in p)Object.prototype.hasOwnProperty.call(p,r)&&(o=str(r,p),o&&u.push(quote(r)+(gap?": ":":")+o));return o=0===u.length?"{}":gap?"{\n"+gap+ 50 | u.join(",\n"+gap)+"\n"+i+"}":"{"+u.join(",")+"}",gap=i,o}}"function"!=typeof Date.prototype.toJSON&&(Date.prototype.toJSON=function(){ 51 | return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+ 52 | f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(){ 53 | return this.valueOf()});var cx,escapable,gap,indent,meta,rep;"function"!=typeof JSON.stringify&& 54 | (escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 55 | meta={"\b":"\\b"," ":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},JSON.stringify=function(t,e,n){var r; 56 | if(gap="",indent="","number"==typeof n)for(r=0;n>r;r+=1)indent+=" ";else"string"==typeof n&&(indent=n);if(rep=e, 57 | e&&"function"!=typeof e&&("object"!=typeof e||"number"!=typeof e.length))throw new Error("JSON.stringify");return str("",{"":t})}), 58 | "function"!=typeof JSON.parse&&(cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g, 59 | JSON.parse=function(text,reviver){function walk(t,e){var n,r,o=t[e];if(o&&"object"==typeof o)for(n in o)Object.prototype.hasOwnProperty.call(o,n)&& 60 | (r=walk(o,n),void 0!==r?o[n]=r:delete o[n]);return reviver.call(t,e,o)}var j;if(text=String(text),cx.lastIndex=0,cx.test(text)&& 61 | (text=text.replace(cx,function(t){return"\\u"+("0000"+t.charCodeAt(0).toString(16)).slice(-4)})), 62 | /^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@") 63 | .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]") 64 | .replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return j=eval("("+text+")"),"function"==typeof reviver?walk({"":j},""):j; 65 | throw new SyntaxError("JSON.parse")})}(); 66 | /*-------------------------------------------------------------------------------------------------------------------------*/ 67 | -------------------------------------------------------------------------------- /Save Open Docs.jsx: -------------------------------------------------------------------------------- 1 | /** * @author Scott Lewis * @copyright 2017 Scott Lewis * @version 1.0.0 * @url http://github.com/iconifyit * * ABOUT: * * This script demonstrates how to implement a progress bar in your script. * * USAGE: * * 1. Place this script in Applications > Adobe Illustrator > Presets > en_US > Scripts * 2. Restart Adobe Illustrator to activate the script * 3. The script will be available under menu File > Scripts > Ai Sessions * * NO WARRANTIES: * * You are free to use, modify, and distribute this script as you see fit. * No credit is required but would be greatly appreciated. * * THIS SCRIPT IS OFFERED AS-IS WITHOUT ANY WARRANTY OR GUARANTEES OF ANY KIND. * YOU USE THIS SCRIPT COMPLETELY AT YOUR OWN RISK AND UNDER NO CIRCUMSTANCES WILL * THE DEVELOPER AND/OR DISTRIBUTOR OF THIS SCRIPT BE HELD LIABLE FOR DAMAGES OF * ANY KIND INCLUDING LOSS OF DATA OR DAMAGE TO HARDWARE OR SOFTWARE. IF YOU DO * NOT AGREE TO THESE TERMS, DO NOT USE THIS SCRIPT. */ /** * Declare the target app. */ #target illustrator /** * Include the libraries we need. */ #includepath "/Users/scott/github/iconify/jsx-common/"; #include "JSON.jsxinc"; #include "Utils.jsxinc"; #include "Logger.jsxinc"; #include "Helpers.jsx"; /** * Name that script. */ #script "Save Open Docs"; /** * Disable Illustrator's alerts. */ // Utils.displayAlertsOff(); /** * Run the script using the Module pattern. This pattern isn't required, * but it is a nice clean and organized way to write the code. It also avoids * cluttering the global scope. */ var MyModule = (function(CONFIG) { /** * The local scope logger object. * @type {Logger} */ var logger = new Logger(CONFIG.APP_NAME, CONFIG.LOGFOLDER); function doSaveDocs() { for (i = 0; i < app.documents.length; i++) { app.activeDocument = app.documents[i]; app.activeDocument.save(); } } /** * Get the current timestamp. * @returns {number} * @private */ function now() { return (new Date()).getTime(); } function getPathItems(src) { var pathItems = []; var groupItems = []; var compoundPathItems = []; var pageItems = []; if (isDefined(src.pathItems)) { pathItems = pathItems.concat(src.pathItems); $.writeln("src.pathItems : " + src.pathItems.length); } if (isDefined(src.pageItems)) { for (var i = 0; i < src.pageItems.length; i++) { var thisItem = src.pageItems[i]; pathItems = pathItems.concat(getPathItems(thisItem)); $.writeln("src.pageItems : " + getPathItems(thisItem).length); } } if (isDefined(src.groupItems)) { for (var i = 0; i < src.groupItems.length; i++) { var thisItem = src.groupItems[i]; pathItems = pathItems.concat(getPathItems(thisItem)); $.writeln("src.groupItems : " + getPathItems(thisItem).length); } } if (isDefined(src.compoundPathItems)) { for (var i = 0; i < src.compoundPathItems.length; i++) { var thisItem = src.compoundPathItems[i]; pathItems = pathItems.concat(getPathItems(thisItem)); $.writeln("src.compoundPathItems : " + getPathItems(thisItem).length); } } return pathItems; } function getSource(object) { try { object.toSource(); } catch(e) { return e.message; } } function getSelectedPathItems() { var doc = app.activeDocument; var selected = [], pathItems = doc.pathItems; for (var i=0; i 0 ) { // doSaveDocs(); var doc = app.activeDocument; // doc.pathItems[0].selected = true; _selectByUUID('d05fd8b7-7e82-4d3a-b350-cd0866dad6cc'); // $.writeln( getSource(selection) ); // alert( getPathItems(selection).length ); return; try { for (x in selection) { if (typeof(selection[x]) == 'function') continue; if (selection[x].typename == 'PathItem') { svgCoords = pathItemToSVG( selection[x] ); $.writeln( svgCoords ); // $.writeln( SVGToPathPointArray( svgCoords ) ); } } } catch(e) { $.writeln(e); } return void(0); } else { alert("There are no open documents"); } try { userInteractionLevel = originalInteractionLevel; } catch(ex) {/*Exit Gracefully*/} } /** * Returns the public module object/interface. */ return { /** * Runs the module code. */ run: function() { main(); } } })({ APP_NAME : "save-open-docs", LOGFOLDER : (new Folder($.getenv("HOME"))).absoluteURI + "/ai-logs/" }); /** * Run the module. */ MyModule.run(); -------------------------------------------------------------------------------- /Contact Sheet/Progress.js: -------------------------------------------------------------------------------- 1 | /** 2 | * The MIT License (MIT) 3 | * 4 | * Copyright (c) 2017 Scott Lewis 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in 14 | * all copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | * THE SOFTWARE. 23 | * 24 | */ 25 | 26 | /** 27 | * The base Progress class. 28 | * @constructor 29 | */ 30 | function Progress( options, show ) { 31 | 32 | this.top = 0; 33 | this.left = 0; 34 | this.width = 450; 35 | this.height = 130; 36 | 37 | this.minvalue = 0; 38 | this.maxvalue = 100; 39 | 40 | this.label = ""; 41 | 42 | this.window = null; 43 | this.panel = null; 44 | 45 | if ( typeof(options) != "undefined" ) { 46 | for (key in options) { 47 | if (this.hasOwnProperty(key)) { 48 | this[key] = options[key]; 49 | } 50 | } 51 | this.init( this.minvalue, this.maxvalue, this.label ); 52 | } 53 | 54 | if (show) this.show(); 55 | } 56 | 57 | /** 58 | * Initialize start settings. 59 | * @param {integer} start 60 | * @param {integer} end 61 | */ 62 | Progress.prototype.init = function(start, end, message) { 63 | 64 | var top = 0, 65 | right = 0, 66 | bottom = 0, 67 | left = 0; 68 | 69 | try { 70 | this.minvalue = start; 71 | this.maxvalue = end; 72 | this.label = message; 73 | 74 | this.top = 0; 75 | this.left = 0; 76 | this.width = 450; 77 | this.height = 140; 78 | 79 | if ( bounds = getScreenSize() ) { 80 | left = Math.abs(Math.ceil((bounds.width/2) - (this.width/2))); 81 | top = Math.abs(Math.ceil((bounds.height/2) - (this.height/2))); 82 | } 83 | 84 | this.window = new Window( 85 | 'palette', 86 | 'Progress', 87 | [left, top, left + this.width, top + this.height] 88 | ); 89 | 90 | this.window.pnl = this.window.add( 91 | 'panel', 92 | [10, 10, 440, 130], 93 | 'Progress' 94 | ); 95 | 96 | this.window.pnl.progBar = this.window.pnl.add( 97 | 'progressbar', 98 | [20, 65, 410, 90], 99 | 0, 100 | this.maxvalue 101 | ); 102 | 103 | this.window.pnl.progBarLabel = this.window.pnl.add( 104 | 'statictext', 105 | [20, 20, 410, 35], 106 | "Item 0 of " + this.maxvalue 107 | ); 108 | 109 | this.window.pnl.progBarLabel2 = this.window.pnl.add( 110 | 'statictext', 111 | [20, 35, 410, 60], 112 | (typeof(this.label) != "undefined" ? " " + this.label : "" ) 113 | ); 114 | } 115 | catch(e) {alert(e)} 116 | 117 | function getScreenSize() { 118 | var screen; 119 | 120 | for (i=0; i<$.screens.length; i++) { 121 | if ($.screens[i].primary == true) { 122 | screen = $.screens[i]; 123 | screen.width = screen.right - screen.left; 124 | screen.height = screen.bottom - screen.top; 125 | } 126 | } 127 | return screen; 128 | } 129 | 130 | return this; 131 | }; 132 | 133 | /** 134 | * Show the progress bar. 135 | */ 136 | Progress.prototype.show = function() { 137 | try { this.close(); } catch(e){}; 138 | this.window.show(); 139 | 140 | return this; 141 | }; 142 | 143 | /** 144 | * Update the progress bar message & counter values. 145 | * @param {string} theMessage 146 | */ 147 | Progress.prototype.update = function( theMessage ) { 148 | 149 | this.increment(); 150 | 151 | this.text( 'Item ' + this.value() + ' of ' + this.max(), theMessage ); 152 | 153 | $.sleep(10); 154 | this.window.update(); 155 | 156 | return this; 157 | }; 158 | 159 | /** 160 | * Set or get the progress text. 161 | * @param {string} theValue 162 | * @returns {*} 163 | */ 164 | Progress.prototype.text = function( firstLine, secondLine ) { 165 | if (typeof(firstLine) != "undefined") { 166 | this.window.pnl.progBarLabel.text = firstLine; 167 | } 168 | if (typeof(secondLine) != "undefined") { 169 | this.window.pnl.progBarLabel2.text = secondLine; 170 | } 171 | return this.window.pnl.progBarLabel.text + 172 | this.window.pnl.progBarLabel2.text; 173 | }; 174 | 175 | /** 176 | * Set or get the progress current value. 177 | * @param {integer} theValue 178 | * @returns {*} 179 | */ 180 | Progress.prototype.value = function( theValue ) { 181 | if (typeof(theValue) != "undefined") { 182 | this.window.pnl.progBar.value = theValue; 183 | } 184 | return this.window.pnl.progBar.value; 185 | }; 186 | 187 | /** 188 | * Get or set the minimum value. 189 | * @param {integer} theValue 190 | */ 191 | Progress.prototype.min = function( theValue ) { 192 | if (typeof(theValue) != "undefined") { 193 | this.window.pnl.progBar.minvalue = theValue; 194 | } 195 | this.window.pnl.progBar.minvalue; 196 | 197 | return this; 198 | }; 199 | 200 | /** 201 | * Get or set the maximum value. 202 | * @param {integer} theValue 203 | * @returns {number|integer|*} 204 | */ 205 | Progress.prototype.max = function( theValue ) { 206 | if (typeof(theValue) != "undefined") { 207 | this.window.pnl.progBar.maxvalue = theValue; 208 | } 209 | return this.window.pnl.progBar.maxvalue; 210 | }; 211 | 212 | /** 213 | * Increment the counter value. 214 | * @returns {*} 215 | */ 216 | Progress.prototype.increment = function() { 217 | this.window.pnl.progBar.value++; 218 | return this.window.pnl.progBar.value; 219 | }; 220 | 221 | /** 222 | * Close the progress bar. 223 | */ 224 | Progress.prototype.close = function() { 225 | this.window.close(); 226 | }; 227 | -------------------------------------------------------------------------------- /Group Overlapping Objects.jsx: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////// 2 | //Group Overlapping (Beta) -- CS, CS2, CS3 3 | //>=-------------------------------------- 4 | // 5 | // Groups all overlapping objects in selection into discreet groups. 6 | // The definition for 'overlaping' is based on objects bounding boxes, not their actual geometry. 7 | // Each new groups zOrder is determined by the depth of the front-most object in each group. 8 | // There is no limit to the number of groups created. 9 | // Any non-overlapping objects are ignored. 10 | // 11 | // Note: Currently, this is not very efficient code. It works well on small groups (less than 120 objects) 12 | // and works faster on smaller groupings. Running this on a huge number of objects will likely crash illustrator. 13 | // It serves my purposes, but test it's limits on your machine, and use at your own risk. 14 | // On a 2.53GHz P4, a group of 100 objects took 20 seconds with 2 groups. 15 | // 16 | // 17 | //>=-------------------------------------- 18 | // JS code (c) copyright: John Wundes ( john@wundes.com ) www.wundes.com 19 | //copyright full text here: http://www.wundes.com/js4ai/copyright.txt 20 | ////////////////////////////////////////////////////////////////// 21 | //this little section is just for testing 22 | //the number of times each function is called. 23 | var testmode = 0; 24 | var t1 = t2 = t3 = t4 = t5 = t6 = t7 = 0; 25 | var testmsg = ""; 26 | // 27 | // 28 | // 29 | var go = true; 30 | if (selection.length > 120) { 31 | go = confirm("You have selected " + selection.length + " objects. It is highly recommended that you select less than 120 objects at a time. Do you want to continue anyway?"); 32 | 33 | } 34 | if (selection.length > 1 && go == true) { 35 | var groups = 0; 36 | var slen = selection.length; 37 | var hitList = new Array(slen); 38 | var groupArr = new Array(slen); 39 | // for each element in selection 40 | for (var sx = 0; sx < slen; sx++) { 41 | //t6++; //---------------------------------------------loop tracker 42 | var tArr = new Array(0); 43 | // for each element in selection (again) 44 | for (var si = 0; si < slen; si++) { 45 | //t7++; //-------------------------------------loop tracker 46 | groupArr[sx] = tArr; 47 | //note each object hits itself once. 48 | if (hitTest(selection[sx], selection[si])) { 49 | groupArr[sx].push(selection[si]); 50 | } 51 | } 52 | } 53 | 54 | minimize(groupArr); 55 | var zError = 0; 56 | var gaLen = groupArr.length; 57 | for (var each = 0; each < gaLen; each++) { 58 | if (groupArr[each].length > 1) { 59 | groupArr[each].sort(sortBy_zOrder); 60 | } 61 | if (zError == 1) { 62 | alert("cannot read some objects zOrderPosition"); 63 | } 64 | //alert("halftime"); 65 | for (var each = 0; each < gaLen; each++) { 66 | t1++; //----------------------------------------------loop tracker 67 | if (groupArr[each].length > 1) { 68 | groups++; 69 | groupAll(groupArr[each]); 70 | } 71 | } 72 | // 73 | //---all done with main code, now display statistics if you care... 74 | // 75 | testmsg = "\nObjects processed: " + t1 + "\nObjects grouped: " + t2 + "\nObjects ignored: " + (t1 - t2); 76 | 77 | if (testmode == 1) { 78 | testmsg += "\n\n---testmode data---\nhits compared: " + t5 + "\nfunction 'minimize' called: " + t3 + "\nitems tested within 'minimize': " + t4; 79 | "\nelements: " + t6 + "\nelements*elements: " + t7; 80 | } 81 | 82 | var x = 0; 83 | 84 | while (x < selection.length) { 85 | 86 | if (selection[x].name == "wundes_GO_group") { 87 | selection[x].name = ""; 88 | } else { 89 | selection[x].selected = false; 90 | x--; 91 | } 92 | x++; 93 | } 94 | redraw(); 95 | alert(groups + " groups created.\n----------------" + testmsg); 96 | } 97 | 98 | 99 | } 100 | //-----------------------------------------------------------> 101 | //--------------------------------functions------------------< 102 | //-----------------------------------------------------------> 103 | 104 | 105 | function sortBy_zOrder(a, b) { 106 | if (a.zOrderPosition == undefined) { 107 | alert(a.zOrderPosition); 108 | zError = 1; 109 | return 0; 110 | } 111 | var x = Number(a.zOrderPosition); 112 | var y = Number(b.zOrderPosition); 113 | 114 | 115 | return ((x < y) ? -1 : ((x > y) ? 1 : 0)); 116 | } 117 | 118 | function groupAll(arr) { 119 | var tempGroup = arr[0].parent.groupItems.add(); 120 | 121 | tempGroup.move(arr[0], ElementPlacement.PLACEBEFORE); 122 | var max = arr.length; 123 | for (var i = max - 1; i >= 0; i--) { 124 | t2++; //-----------------------------------------loop tracker 125 | arr[i].move(tempGroup, ElementPlacement.INSIDE); 126 | } 127 | //name the object for selection at end... (will be removed later) 128 | tempGroup.name = "wundes_GO_group"; 129 | tempGroup.selected = true; 130 | 131 | } 132 | //---------------hitTest functions --------------- 133 | 134 | 135 | function hitTest(a, b) { 136 | var OK = 0; 137 | if (isWithinX(a, b) || isWithinX(b, a)) { 138 | OK++; 139 | } 140 | if (isWithinY(a, b) || isWithinY(b, a)) { 141 | OK++; 142 | } 143 | if (OK < 2) { 144 | //alert("miss."); 145 | return false; 146 | } else { 147 | //alert("Hit!") 148 | return true; 149 | } 150 | } 151 | 152 | function isWithinX(a, b) { 153 | var p1 = a.geometricBounds[0]; 154 | var p2 = b.geometricBounds[0]; 155 | if (p2 <= p1 && p1 <= p2 + b.width) { 156 | return true; 157 | } else { 158 | return false; 159 | } 160 | } 161 | 162 | function isWithinY(a, b) { 163 | var p3 = a.geometricBounds[1]; 164 | var p4 = b.geometricBounds[1]; 165 | if (p3 >= p4 && p4 >= (p3 - a.height)) { 166 | return true; 167 | } 168 | return false; 169 | } 170 | 171 | /* 172 | //-----------------------------------OK, finding groups is done, now do the grouping--------------- 173 | */ 174 | 175 | function itemize(a) { 176 | var out = ""; 177 | return (a.join("\n")); 178 | } 179 | 180 | function minimize(arr) { 181 | for (var e in arr) { 182 | t3++; //-----------------------------------------loop tracker 183 | for (ot in arr) { 184 | t4++; //-------------------------------------loop tracker 185 | if (arr[e] != arr[ot]) { 186 | //if it's not THIS element, 187 | //test for overlaps 188 | if (overlaps(arr[e], arr[ot])) { 189 | merge(arr[e], arr[ot]); 190 | arr[e] = new Array(0); 191 | minimize(arr); 192 | break; 193 | } 194 | } 195 | } 196 | } 197 | 198 | } 199 | 200 | function merge(a, b) { 201 | var alen = a.length; 202 | for (var all = 0; all < alen; all++) { 203 | if (contains(b, a[all])) { 204 | //do nothing 205 | } else { 206 | 207 | b.push(a[all]); 208 | 209 | } 210 | } 211 | 212 | } 213 | 214 | function contains(ar, i) { 215 | for (var all in ar) { 216 | if (ar[all] == i) { 217 | return true; 218 | } 219 | } 220 | return false; 221 | } 222 | 223 | 224 | function overlaps(ar1, ar2) { 225 | for (var each in ar1) { 226 | t5++; //------------------------------------loop tracker 227 | if (contains(ar2, ar1[each])) { // 228 | return true; 229 | } 230 | } 231 | return false; 232 | } -------------------------------------------------------------------------------- /Contact Sheet/FileList.js: -------------------------------------------------------------------------------- 1 | /** 2 | * FileListError class. 3 | * @param message 4 | * @param stack 5 | * @constructor 6 | */ 7 | var FileListError = function(message, stack) { 8 | this.name = "FileListError"; 9 | this.message = message || "Unknown FileListError"; 10 | this.stack = stack; 11 | }; 12 | FileListError.prototype = Error.prototype; 13 | 14 | /** 15 | * File Extensions constants. 16 | * @type {{JPG: string, PDF: string, SVG: string, GIF: string, AI: string, PNG: string, EPS: string}} 17 | */ 18 | var FileTypes = { 19 | 20 | SVG : "SVG", 21 | EPS : "EPS", 22 | AI : "AI", 23 | PDF : "PDF", 24 | PNG : "PNG", 25 | JPG : "JPG", 26 | GIF : "GIF", 27 | 28 | toRegex : function(theType) { 29 | if (typeof(FileTypes[theType.toUpperCase()]) == 'string') { 30 | return new RegExp(theType.toLowerCase(), 'ig'); 31 | } 32 | } 33 | }; 34 | 35 | /** 36 | * Class to get list of files. If you pass a file type or types array, the class 37 | * will return the list immediately. If you pass only the source folder, an interface 38 | * with several methods is returned. 39 | * @param rootFolder 40 | * @param fileTypes 41 | * @returns {*} 42 | * @constructor 43 | */ 44 | var FileList = function(rootFolder, fileTypes) { 45 | 46 | if (typeof rootFolder == 'string') { 47 | rootFolder = new Folder(rootFolder); 48 | } 49 | 50 | if (typeof fileTypes != 'undefined') { 51 | return _getFiles(true, fileTypes); 52 | } 53 | 54 | /** 55 | * Get all files in subfolders. 56 | * @param {Folder} srcFolder The root folder from which to merge SVGs. 57 | * @returns {Array} Array of nested files. 58 | */ 59 | function getFilesInSubfolders( srcFolder, recurse, fileTypes ) { 60 | 61 | if (typeof recurse != 'boolean') { 62 | recurse = false; 63 | } 64 | 65 | if (typeof fileTypes == 'string') { 66 | fileTypes = [fileTypes]; 67 | } 68 | 69 | if ( ! (srcFolder instanceof Folder)) return; 70 | 71 | var theFolders = getSubFolders(srcFolder), 72 | theFileList = getFilesInFolder(srcFolder, fileTypes); 73 | 74 | if (! recurse || theFolders.length == 0) { 75 | theFileList = Array.prototype.concat.apply([], getFilesInFolder(srcFolder, fileTypes)); 76 | } 77 | else { 78 | for (var x=0; x < theFolders.length; x++) { 79 | theFileList = Array.prototype.concat.apply(theFileList, getFilesInFolder(theFolders[x], fileTypes)); 80 | } 81 | } 82 | 83 | return theFileList; 84 | } 85 | 86 | /** 87 | * Get all nested subfolders in theFolder. 88 | * @param theFolder 89 | * @returns {*} 90 | */ 91 | function getSubFolders(theFolder) { 92 | var subFolders = []; 93 | var myFileList = theFolder.getFiles(); 94 | for (var i = 0; i < myFileList.length; i++) { 95 | var myFile = myFileList[i]; 96 | if (myFile instanceof Folder) { 97 | subFolders.push(myFile); 98 | subFolders = Array.prototype.concat.apply( 99 | subFolders, 100 | getSubFolders(myFile) 101 | ); 102 | } 103 | } 104 | return subFolders; 105 | } 106 | 107 | /** 108 | * Gets the files in a specific source folder. 109 | * 110 | * NOTE: You may notice that in the code below we do not use the Illustrator File method 111 | * `theFolder.getFiles(/\.svg$/i)` to scan the folder for a specific file type, even though 112 | * it would be more efficient. The reason is that from time-to-time the MacOS will not correctly 113 | * identify the file type and the list comes back empty when it is, in fact, not empty. To prevent 114 | * the script from randomly stop working and require a system restart, we use a slightly less 115 | * efficient but more reliable method to identify the file extension. 116 | * 117 | * @param {Folder} The folder object 118 | * @returns {Array} 119 | */ 120 | function getFilesInFolder(theFolder, fileTypes) { 121 | 122 | var theFile, 123 | theExt, 124 | fileList = []; 125 | 126 | // Make sure we are working with an array if a type is provided. 127 | 128 | if (typeof fileTypes == 'string') { 129 | fileTypes = [fileTypes]; 130 | } 131 | 132 | fileList = theFolder.getFiles(); 133 | 134 | if (typeof fileTypes.length != 'undefined' && fileTypes.length > 0) { 135 | var filtered = []; 136 | for (var t = 0; t < fileTypes.length; t++) { 137 | var fileType = fileTypes[t]; 138 | 139 | for (var i = 0; i < fileList.length; i++) { 140 | 141 | theFile = fileList[i]; 142 | theExt = theFile.name.split(".").pop(); 143 | 144 | if ( theExt.trim().toUpperCase() == fileType.trim().toUpperCase() ) { 145 | filtered.push(theFile); 146 | } 147 | } 148 | } 149 | fileList = filtered; 150 | } 151 | 152 | return fileList; 153 | } 154 | 155 | /** 156 | * Get the file type from file extension. 157 | * @param theFile 158 | * @returns {string} 159 | */ 160 | function getFileType(theFile) { 161 | return theFile.name.split(".").pop().trim().toUpperCase(); 162 | } 163 | 164 | /** 165 | * List files except excluded types. 166 | * @param rootFolder 167 | * @param recurse 168 | * @param exclude 169 | * @returns {any} 170 | */ 171 | function getAllFilesExcept(rootFolder, recurse, exclude) { 172 | 173 | if (typeof exclude == 'undefineed') { 174 | return new Error('Array of excluded types required in FileList.getAllFilesExcept'); 175 | } 176 | 177 | var files = getFilesInSubfolders(rootFolder, recurse); 178 | 179 | var filtered = []; 180 | for (var i = 0; i < files.length; i++) { 181 | if (excluded.indexOf( getFileType(files[i]) ) == -1) { 182 | filtered.push(files[i]); 183 | } 184 | } 185 | return filtered; 186 | } 187 | 188 | /** 189 | * Get the file list. 190 | * @param recurse 191 | * @param fileTypes 192 | * @returns {Array} 193 | * @private 194 | */ 195 | function _getFiles(recurse, fileTypes) { 196 | if (typeof recurse != 'boolean') recurse = false; 197 | return getFilesInSubfolders(rootFolder, recurse, fileTypes); 198 | } 199 | 200 | /** 201 | * Public interface. 202 | */ 203 | return { 204 | getFiles : function(recurse, fileTypes) { 205 | return _getFiles(recurse, fileTypes); 206 | }, 207 | getAllFilesExcept : function(recurse, excludeTypes) { 208 | return getAllFilesExcept(rootFolder, recurse, excludeTypes); 209 | }, 210 | getFolders : function(recurse) { 211 | if (typeof recurse != 'boolean') recurse = false; 212 | return getSubFolders(recurse); 213 | } 214 | } 215 | }; 216 | -------------------------------------------------------------------------------- /Contact Sheet/.idea/workspace.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 33 | 34 | 35 | /usr/local/bin/bower 36 | 37 | 38 | 39 | true 40 | 41 | false 42 | true 43 | true 44 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 |