├── .eslintrc ├── i18n ├── en.json ├── es.json ├── it.json ├── sk.json ├── pt-BR.json ├── de.json └── fr.json ├── .gitignore ├── test ├── package.json ├── modules │ └── @apostrophecms │ │ └── svg-sprite │ │ └── public │ │ └── svg │ │ ├── places.svg │ │ └── icons-8675309.svg ├── public │ └── three-places.svg └── test.js ├── CHANGELOG.md ├── LICENSE.md ├── package.json ├── .github └── workflows │ └── main.yml ├── index.js ├── README.md └── lib └── import.js /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ "apostrophe" ], 3 | "rules": { 4 | "no-var": 2 5 | } 6 | } -------------------------------------------------------------------------------- /i18n/en.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "SVG Sprite", 3 | "pluralLabel": "SVG Sprites", 4 | "taskUsage": "Imports sprites from registered SVG maps as pieces" 5 | } -------------------------------------------------------------------------------- /i18n/es.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Sprite SVG", 3 | "pluralLabel": "Sprites SVG", 4 | "taskUsage": "Importa sprites de mapas SVG registrados como piezas" 5 | } 6 | -------------------------------------------------------------------------------- /i18n/it.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Sprite SVG", 3 | "pluralLabel": "Sprite SVG", 4 | "taskUsage": "Importa sprite da mappe SVG registrate come pezzi" 5 | } 6 | -------------------------------------------------------------------------------- /i18n/sk.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "SVG Sprite", 3 | "pluralLabel": "SVG Sprity", 4 | "taskUsage": "Importuje sprity z registrovaných SVG máp ako kusy" 5 | } 6 | -------------------------------------------------------------------------------- /i18n/pt-BR.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Sprite SVG", 3 | "pluralLabel": "Sprites SVG", 4 | "taskUsage": "Importa sprites de mapas SVG registrados como peças" 5 | } 6 | -------------------------------------------------------------------------------- /i18n/de.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "SVG Sprite", 3 | "pluralLabel": "SVG Sprites", 4 | "taskUsage": "Importiert Sprites aus registrierten SVG-Karten als Stücke" 5 | } 6 | -------------------------------------------------------------------------------- /i18n/fr.json: -------------------------------------------------------------------------------- 1 | { 2 | "label": "Sprite SVG", 3 | "pluralLabel": "Sprites SVG", 4 | "taskUsage": "Importe des sprites à partir des cartes SVG enregistrées en tant que pièces" 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore MacOS X metadata forks (fusefs) 2 | ._* 3 | package-lock.json 4 | *.DS_Store 5 | node_modules 6 | 7 | # Never commit a CSS map file, anywhere 8 | *.css.map 9 | 10 | # vim swp files 11 | .*.sw* 12 | -------------------------------------------------------------------------------- /test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "-//": "This package.json file is not actually installed.", 3 | "/-/": "Apostrophe requires that all npm modules to be loaded by moog", 4 | "//-": "exist in package.json at project level, which for a test is here", 5 | "dependencies": { 6 | "apostrophe": "^3.9.0", 7 | "@apostrophecms/svg-sprite": "git://github.com/apostrophecms/svg-sprite.git" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.2 (2024-10-31) 4 | 5 | * Adds AI-generated and community reviewed missing translations. 6 | 7 | ## 1.0.1 (2024-04-18) 8 | 9 | - Fix vulnerable dependencies axios, xml2js and mocha to pass npm audit. 10 | 11 | ## 1.0.0 (2022-08-18) 12 | 13 | - Initial stable release. This supports importing sprite map files into Apostrophe to create individual SVG sprite pieces. 14 | -------------------------------------------------------------------------------- /test/modules/@apostrophecms/svg-sprite/public/svg/places.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Apostrophe Technologies 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@apostrophecms/svg-sprite", 3 | "version": "1.0.2", 4 | "description": "Module to power SVG sprite elements as pieces in Apostrophe 3 projects", 5 | "main": "index.js", 6 | "scripts": { 7 | "lint": "npm run eslint", 8 | "eslint": "eslint .", 9 | "test": "npm run lint && mocha" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/apostrophecms/svg-sprite.git" 14 | }, 15 | "homepage": "https://github.com/apostrophecms/svg-sprite#readme", 16 | "author": "Apostrophe Technologies", 17 | "license": "MIT", 18 | "devDependencies": { 19 | "apostrophe": "github:apostrophecms/apostrophe", 20 | "eslint": "^7.9.0", 21 | "eslint-config-apostrophe": "^3.4.0", 22 | "eslint-config-standard": "^14.1.1", 23 | "eslint-plugin-import": "^2.22.0", 24 | "eslint-plugin-node": "^11.1.0", 25 | "eslint-plugin-promise": "^4.2.1", 26 | "eslint-plugin-standard": "^4.0.1", 27 | "mocha": "^10.4.0" 28 | }, 29 | "publishConfig": { 30 | "access": "public" 31 | }, 32 | "dependencies": { 33 | "axios": "^1.6.8", 34 | "glob": "^7.2.0", 35 | "lodash": "^4.17.21", 36 | "xml2js": "^0.6.2" 37 | } 38 | } -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: tests 4 | 5 | # Controls when the action will run. 6 | on: 7 | push: 8 | branches: [ '*' ] 9 | pull_request: 10 | branches: [ '*' ] 11 | 12 | # Allows you to run this workflow manually from the Actions tab 13 | workflow_dispatch: 14 | 15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 16 | jobs: 17 | # This workflow contains a single job called "build" 18 | build: 19 | # The type of runner that the job will run on 20 | runs-on: ubuntu-latest 21 | strategy: 22 | matrix: 23 | node-version: [18, 20] 24 | mongodb-version: [5.0, 6.0, 7.0] 25 | 26 | # Steps represent a sequence of tasks that will be executed as part of the job 27 | steps: 28 | - name: Git checkout 29 | uses: actions/checkout@v2 30 | 31 | - name: Use Node.js ${{ matrix.node-version }} 32 | uses: actions/setup-node@v1 33 | with: 34 | node-version: ${{ matrix.node-version }} 35 | 36 | - name: Start MongoDB 37 | uses: supercharge/mongodb-github-action@1.3.0 38 | with: 39 | mongodb-version: ${{ matrix.mongodb-version }} 40 | 41 | - run: npm install 42 | 43 | - run: npm test 44 | env: 45 | CI: true -------------------------------------------------------------------------------- /test/public/three-places.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/modules/@apostrophecms/svg-sprite/public/svg/icons-8675309.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extend: '@apostrophecms/piece-type', 3 | options: { 4 | label: 'aposSvgs:label', 5 | pluralLabel: 'aposSvgs:pluralLabel', 6 | i18n: { 7 | ns: 'aposSvgs', 8 | browser: true 9 | }, 10 | // Opt out of open graph, SEO, search, and quick create 11 | openGraph: false, 12 | seoFields: false, 13 | searchable: false, 14 | quickCreate: false, 15 | // Auto-publish (no draft state, but you can localize them) 16 | autopublish: true 17 | }, 18 | fields (self) { 19 | const mapChoices = (self.options.maps || []).map(map => { 20 | return { 21 | label: map.label, 22 | value: map.name 23 | }; 24 | }); 25 | 26 | return { 27 | add: { 28 | svgId: { 29 | label: 'SVG symbol ID', 30 | type: 'string', 31 | help: 'ID of the element in the sprite map', 32 | required: true, 33 | readOnly: true 34 | }, 35 | map: { 36 | label: 'Sprite Map', 37 | type: 'select', 38 | choices: mapChoices, 39 | required: true, 40 | readOnly: true 41 | } 42 | }, 43 | group: { 44 | basics: { 45 | fields: [ 'svgId', 'map' ] 46 | } 47 | } 48 | }; 49 | }, 50 | tasks (self) { 51 | const { 52 | importTask 53 | } = require('./lib/import')(self); 54 | 55 | return { 56 | import: { 57 | usage: 'aposSvgs:taskUsage', 58 | task: importTask 59 | } 60 | }; 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | ApostropheCMS logo 3 | 4 |

SVG Sprites for ApostropheCMS

5 |

6 | 7 | 8 | 9 | 10 | GitHub Workflow Status (branch) 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |

19 |
20 | 21 | This module provides an Apostrophe piece type that manages and renders SVG sprites. Sprites can be imported from files in a website codebase or an external source via a URL. 22 | 23 | SVG sprites must be generated by a separate process. The module does not provide functionality to build the sprite files. [See below](#sprite-file-markup) for sprite markup requirements. 24 | 25 | ## Installation 26 | 27 | To install the module, use the command line to run this command in an Apostrophe project's root directory: 28 | 29 | ``` 30 | npm install @apostrophecms/svg-sprite 31 | ``` 32 | 33 | ## Usage 34 | 35 | Configure the SVG Sprite module in the `app.js` file: 36 | 37 | ```javascript 38 | require('apostrophe')({ 39 | shortName: 'my-project', 40 | modules: { 41 | '@apostrophecms/svg-sprite': {} 42 | } 43 | }); 44 | ``` 45 | 46 | The SVG Sprites module should then be configured in its own `index.js` file with information about the sprite maps. Sprite files should be registered in the `maps` option, set to an array of configuration objects. 47 | 48 | ```javascript 49 | // modules/@apostrophecms/svg-sprite/index.js 50 | module.exports = { 51 | options: { 52 | maps: [ 53 | { 54 | label: 'Places Icons', 55 | name: 'places', 56 | file: 'svg/places.svg' 57 | }, 58 | { 59 | label: 'Service Icons', 60 | name: 'services', 61 | file: 'svg/services.svg' 62 | } 63 | ] 64 | } 65 | } 66 | ``` 67 | 68 | The configuration objects include: 69 | 70 | - `label`: A clear label for the group of sprites. 71 | - `name`: A string with no whitespace that is unique within the project. 72 | - `file`: The location of the file. This may be a local file or a URL, as discussed below. 73 | 74 | The sprites can be imported into Apostrophe as pieces by running the module's `import` task. This task will look for each registered sprite file and generate pieces (Apostrophe content) for each SVG. On the command line this task could be started from the project root with the following command: 75 | 76 | ```bash 77 | node app @apostrophecms/svg-sprite:import 78 | ``` 79 | 80 | ### Sprite file location options 81 | 82 | There are three options for registering SVG file locations: 83 | 84 | 1. Use a partial file path to a specific file, e.g., `'svg/places.svg'`. 85 | 2. Use a partial file path with wild card symbols, e.g., `'svg/*-icons.svg'`. See the [Glob package documentation](https://www.npmjs.com/package/glob#glob-primer) for acceptable patterns. 86 | 3. Use a URL for an externally hosted file, e.g., `'http://myfiles.net/svg/icons.svg'`. 87 | 88 | When using the partial file path options, the module will look for those files in its own `public` directory: `modules/@apostrophecms/svg-sprite/public/`. For example, `'svg/places.svg'` would reference a file at `modules/@apostrophecms/svg-sprite/public/svg/places.svg` in the code base. 89 | 90 | ### Sprite file markup 91 | 92 | Sprite files use the [SVG `symbol` element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/symbol) to include multiple SVG images within a single `svg` tag. See the [CSS-Tricks](https://css-tricks.com/svg-symbol-good-choice-icons/) guide for more information about how to construct and use these sprite files. 93 | 94 | **Requirements for this module include:** 95 | - Sprite maps must be formatted so that all `...` elements are on the same node level. This simply means that `symbol` tags should not be nested within other `symbol` tags. 96 | - `symbol` tags must have an `id` attribute, e.g., `...`. 97 | - `symbol` tags can *optionally* have a `title` attribute that will be used as the imported piece's title field, e.g., `...` 98 | 99 | Here is an example of sprite file markup (with the `path` values abbeviated): 100 | 101 | ```html 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | ``` 111 | 112 | ### Using SVG sprite pieces 113 | 114 | The primary properties we use to reference individual SVG symbols are: 115 | - `file`: The file path or URL to the full sprite map. This file still includes all symbols that were part of that original map file. 116 | - `svgId`: The `id` property of the individual SVG symbol. We have to use this in combination with the file path to get a specific symbol. 117 | - `map`: The `map` name property can be used to quickly find one of the sprite maps that were configured in the module's `maps` array. 118 | 119 | HTML markup using an individual SVG symbol might look like the example below. The example uses `svgSprite` as a reference to the individual piece content. A project might reference sprite pieces using a relationship field, for example. 120 | 121 | ```django 122 | 123 | 124 | 125 | ``` 126 | -------------------------------------------------------------------------------- /lib/import.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const glob = require('glob'); 3 | const axios = require('axios'); 4 | const xml2js = require('xml2js'); 5 | const _ = require('lodash'); 6 | 7 | module.exports = function (self) { 8 | return { 9 | async importTask () { 10 | const maps = self.options.maps; 11 | 12 | for (const map of maps) { 13 | const { data, updatedMap } = await loadMap(map); 14 | 15 | const svgs = await parseMap(data, updatedMap); 16 | 17 | await evaluateForUpsert(svgs); 18 | } 19 | } 20 | }; 21 | 22 | async function loadMap(map) { 23 | const pattern = /(http(s)?)/gi; 24 | 25 | if (pattern.test(map.file)) { 26 | return loadMapFromUrl(map); 27 | 28 | } else { 29 | // file is a relative file path 30 | const base = `${self.apos.rootDir}/modules/@apostrophecms/svg-sprite/public/`; 31 | const path = base + map.file; 32 | 33 | if (path.includes('*')) { 34 | return loadMapFromGlob(base, path, map); 35 | } else { 36 | return loadMapFromPath(base, path, map); 37 | } 38 | } 39 | } 40 | 41 | async function loadMapFromUrl (map) { 42 | // file is a full url, load it via axios module 43 | const response = await axios.get(map.file); 44 | 45 | if (response.status >= 400 && response.status < 500) { 46 | throw self.apos.error('notfound'); 47 | } else if (response.status !== 200) { 48 | self.apos.util.error(response); 49 | throw self.apos.error('error'); 50 | } 51 | 52 | const data = response.data; 53 | 54 | return { 55 | data, 56 | updatedMap: map 57 | }; 58 | } 59 | 60 | async function loadMapFromGlob(base, path, map) { 61 | const readFile = require('util').promisify(fs.readFile); 62 | const asyncGlob = require('util').promisify(glob); 63 | const files = await asyncGlob(path); 64 | 65 | if (files.length) { 66 | const data = await readFile(files[0]); 67 | 68 | // Get the path relative to the module's public folder 69 | const file = files[0].substring(base.length); 70 | // Correct map.file to point to the current actual file, 71 | map.file = file; 72 | 73 | map.finalFile = `${self.apos.asset.getAssetBaseUrl()}/modules/@apostrophecms/my-svg-sprite/${file}`; 74 | 75 | return { 76 | data, 77 | updatedMap: map 78 | }; 79 | 80 | } else { 81 | self.apos.util.error(path + ' does not match anything, cannot continue'); 82 | return { 83 | data: null, 84 | updatedMap: map 85 | }; 86 | } 87 | } 88 | 89 | async function loadMapFromPath(base, path, map) { 90 | const readFile = require('util').promisify(fs.readFile); 91 | if (fileExists(path)) { 92 | // TODO: Should this be using the my- prefix? 93 | map.finalFile = `${self.apos.asset.getAssetBaseUrl()}/modules/@apostrophecms/my-svg-sprite/${map.file}`; 94 | 95 | const data = await readFile(path); 96 | 97 | return { 98 | data, 99 | updatedMap: map 100 | }; 101 | 102 | } else { 103 | self.apos.util.error(path + ': no path provided, cannot continue'); 104 | return { 105 | data: null, 106 | updatedMap: map 107 | }; 108 | } 109 | } 110 | 111 | async function parseMap(xml = '', map = {}) { 112 | const parseString = require('util').promisify(xml2js.parseString); 113 | 114 | const svgs = []; 115 | const result = await parseString(xml); 116 | 117 | let symbols = findInObj(result, 'symbol'); 118 | 119 | if (!symbols.length) { 120 | self.apos.util.error('Could not find an array of elements in map ' + map.label); 121 | 122 | throw self.apos.error('invalid'); 123 | } 124 | 125 | if (symbols[0] && symbols[0].symbol) { 126 | symbols = symbols[0].symbol; 127 | } else { 128 | self.apos.util.error('Error occurred parsing array of symbols in map ' + map.label); 129 | 130 | throw self.apos.error('error'); 131 | } 132 | 133 | symbols.forEach(function (symbol) { 134 | if (symbol.$.id) { 135 | svgs.push({ 136 | symbol: symbol.$, 137 | file: map.finalFile || map.file, 138 | map: map.name 139 | }); 140 | } else { 141 | self.apos.util.error('SVG is malformed or has no ID property'); 142 | 143 | throw self.apos.error('invalid'); 144 | } 145 | }); 146 | 147 | return svgs; 148 | 149 | } 150 | 151 | async function evaluateForUpsert(svgs) { 152 | const req = self.apos.task.getReq(); 153 | 154 | for (const svg of svgs) { 155 | 156 | const docs = await self.find(req, { 157 | svgId: svg.symbol.id 158 | }, {}).toArray(); 159 | 160 | if (docs.length) { 161 | // i have a doc, update it 162 | await updatePiece(req, docs[0], svg); 163 | } else { 164 | // i don't have a doc, insert it 165 | await insertPiece(svg); 166 | } 167 | } 168 | } 169 | 170 | async function insertPiece(svg) { 171 | const req = self.apos.task.getReq(); 172 | const piece = self.newInstance(); 173 | 174 | if (svg.symbol.title) { 175 | piece.title = self.apos.launder.string(svg.symbol.title); 176 | } else { 177 | piece.title = self.apos.launder.string(svg.symbol.id); 178 | } 179 | 180 | piece.svgId = svg.symbol.id; 181 | piece.file = svg.file; 182 | piece.map = svg.map; 183 | 184 | await self.insert(req, piece); 185 | } 186 | 187 | async function updatePiece(req, doc, svg) { 188 | const updatedDoc = await self.findOneForEditing(req, { _id: doc._id }); 189 | 190 | if (svg.symbol.title) { 191 | updatedDoc.title = self.apos.launder.string(svg.symbol.title); 192 | } else { 193 | updatedDoc.title = self.apos.launder.string(svg.symbol.id); 194 | } 195 | 196 | updatedDoc.file = svg.file; 197 | updatedDoc.map = svg.map; 198 | 199 | await self.update(req, updatedDoc); 200 | } 201 | 202 | function fileExists(path) { 203 | if (fs.existsSync(path)) { 204 | return true; 205 | } else { 206 | return false; 207 | } 208 | } 209 | 210 | function findInObj(obj, key) { 211 | 212 | if (_.has(obj, key)) { 213 | return [ obj ]; 214 | } 215 | 216 | return _.flatten(_.map(obj, function (v) { 217 | return typeof v === 'object' ? findInObj(v, key) : []; 218 | }), true); 219 | } 220 | }; 221 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | const assert = require('assert'); 2 | const testUtil = require('apostrophe/test-lib/test'); 3 | 4 | describe('SVG Sprites', function () { 5 | let apos; 6 | let svgSprites; 7 | 8 | this.timeout(10000); 9 | 10 | after(async function () { 11 | testUtil.destroy(apos); 12 | testUtil.destroy(apos2); 13 | testUtil.destroy(apos3); 14 | }); 15 | 16 | it('should be a property of the apos object', async function () { 17 | apos = await testUtil.create({ 18 | shortname: 'test-exporter', 19 | testModule: true, 20 | modules: { 21 | '@apostrophecms/express': { 22 | options: { 23 | session: { secret: 'test-the-svgs' } 24 | } 25 | }, 26 | '@apostrophecms/svg-sprite': { 27 | options: { 28 | maps: [ 29 | { 30 | label: 'Places Icons', 31 | name: 'places', 32 | file: 'svg/places.svg' 33 | } 34 | ] 35 | } 36 | } 37 | } 38 | }); 39 | 40 | assert(apos.modules['@apostrophecms/svg-sprite']); 41 | svgSprites = apos.modules['@apostrophecms/svg-sprite']; 42 | }); 43 | 44 | it('can run the import task', async () => { 45 | try { 46 | await apos.task.invoke('@apostrophecms/svg-sprite:import'); 47 | } catch (error) { 48 | assert(!error); 49 | } 50 | }); 51 | 52 | let howMany; 53 | let firstSprites; 54 | 55 | it('can find imported pieces', async function() { 56 | const req = apos.task.getReq(); 57 | 58 | firstSprites = await svgSprites.find(req, {}) 59 | .toArray(); 60 | 61 | assert(firstSprites); 62 | assert(firstSprites.length === 2); 63 | howMany = firstSprites.length; 64 | }); 65 | 66 | it('can find the SVG file path on the piece', async function () { 67 | const assetPath = apos.asset.getAssetBaseUrl() + '/modules/@apostrophecms/my-svg-sprite/svg/places.svg'; 68 | assert(firstSprites[0].file === assetPath); 69 | }); 70 | 71 | it('marks existing sprites', async function() { 72 | try { 73 | await apos.doc.db.updateMany({ type: '@apostrophecms/svg-sprite' }, { 74 | $set: { 75 | existing: true 76 | } 77 | }); 78 | } catch (error) { 79 | assert(!error); 80 | } 81 | }); 82 | 83 | it('can re-import', async function() { 84 | try { 85 | await apos.task.invoke('@apostrophecms/svg-sprite:import'); 86 | } catch (error) { 87 | assert(!error); 88 | } 89 | }); 90 | 91 | it('finds the same number of pieces and they are the same pieces', async function() { 92 | const req = apos.task.getReq(); 93 | const pieces = await svgSprites.find(req, {}) 94 | .toArray(); 95 | 96 | assert(pieces); 97 | assert(pieces.length); 98 | assert(pieces.length === howMany); 99 | assert(pieces[0].existing); 100 | }); 101 | 102 | let apos2; 103 | 104 | it('should be a property of the apos2 object', async function () { 105 | const baseUrl = 'http://localhost:7777'; 106 | 107 | apos2 = await testUtil.create({ 108 | shortname: 'test-exporter-2', 109 | testModule: true, 110 | baseUrl, 111 | modules: { 112 | '@apostrophecms/express': { 113 | options: { 114 | port: 7777, 115 | session: { secret: 'test-the-svgs-again' } 116 | } 117 | }, 118 | '@apostrophecms/svg-sprite': { 119 | options: { 120 | maps: [ 121 | { 122 | label: 'Places Icons', 123 | name: 'places', 124 | file: `${baseUrl}/three-places.svg` 125 | } 126 | ] 127 | } 128 | } 129 | } 130 | }); 131 | 132 | assert(apos2.modules['@apostrophecms/svg-sprite']); 133 | }); 134 | 135 | it('can import from a URL', async () => { 136 | const assetUrl = apos2.baseUrl + '/three-places.svg'; 137 | const fileExists = await apos2.http.get(assetUrl); 138 | assert(fileExists); 139 | 140 | try { 141 | // Importer is running from the URL in the apos2 module configuration. 142 | await apos2.task.invoke('@apostrophecms/svg-sprite:import'); 143 | } catch (error) { 144 | console.error(error); 145 | assert(!error); 146 | } 147 | }); 148 | 149 | let secondSprites; 150 | 151 | it('can find URL-imported pieces', async function() { 152 | const req = apos2.task.getReq(); 153 | 154 | secondSprites = await apos2.modules['@apostrophecms/svg-sprite'].find(req, {}) 155 | .toArray(); 156 | 157 | assert(secondSprites); 158 | 159 | assert(secondSprites.length === 3); 160 | }); 161 | 162 | it('can find the SVG file path on the piece', async function () { 163 | const assetPath = `${apos2.baseUrl}/three-places.svg`; 164 | assert(secondSprites[0].file === assetPath); 165 | }); 166 | 167 | let apos3; 168 | 169 | it('should be a property of the apos3 object', async function () { 170 | apos3 = await testUtil.create({ 171 | shortname: 'test-exporter-3', 172 | testModule: true, 173 | modules: { 174 | '@apostrophecms/express': { 175 | options: { 176 | session: { secret: 'test-the-svgs-a-third-time' } 177 | } 178 | }, 179 | '@apostrophecms/svg-sprite': { 180 | options: { 181 | maps: [ 182 | { 183 | label: 'All Icons', 184 | name: 'icons', 185 | file: 'svg/icons-*.svg' 186 | } 187 | ] 188 | } 189 | } 190 | } 191 | }); 192 | 193 | assert(apos3.modules['@apostrophecms/svg-sprite']); 194 | }); 195 | 196 | it('can import with a wild card', async () => { 197 | try { 198 | // Importer is running from the wild card path in the apos3 module 199 | // configuration. 200 | await apos3.task.invoke('@apostrophecms/svg-sprite:import'); 201 | } catch (error) { 202 | console.error(error); 203 | assert(!error); 204 | } 205 | }); 206 | 207 | let thirdSprites; 208 | 209 | it('can find wild card-imported pieces', async function() { 210 | const req = apos3.task.getReq(); 211 | 212 | thirdSprites = await apos3.modules['@apostrophecms/svg-sprite'].find(req, {}) 213 | .toArray(); 214 | 215 | assert(thirdSprites); 216 | 217 | assert(thirdSprites.length === 4); 218 | }); 219 | 220 | it('can find the SVG file path on the piece', async function () { 221 | const assetPath = apos3.asset.getAssetBaseUrl() + '/modules/@apostrophecms/my-svg-sprite/svg/icons-8675309.svg'; 222 | 223 | assert(thirdSprites[2].file === assetPath); 224 | }); 225 | }); 226 | --------------------------------------------------------------------------------