├── renovate.json ├── packages ├── dayjs │ ├── lib │ │ ├── constants.js │ │ ├── templates │ │ │ └── plugin.js │ │ └── module.js │ ├── test │ │ ├── fixture │ │ │ ├── pages │ │ │ │ └── index.vue │ │ │ └── nuxt.config.js │ │ └── module.test.js │ ├── .editorconfig │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── package.json │ └── README.md ├── lozad │ ├── lib │ │ ├── constants.js │ │ ├── templates │ │ │ └── plugin.js │ │ └── module.js │ ├── test │ │ ├── fixture │ │ │ ├── nuxt.config.js │ │ │ └── pages │ │ │ │ └── index.vue │ │ └── module.test.js │ ├── .editorconfig │ ├── .eslintrc.js │ ├── CHANGELOG.md │ ├── package.json │ └── README.md ├── multisite │ ├── test │ │ ├── fixture │ │ │ ├── pages │ │ │ │ └── index.vue │ │ │ └── nuxt.config.js │ │ └── module.test.js │ ├── lib │ │ ├── constants.js │ │ ├── module.js │ │ └── templates │ │ │ └── plugin.js │ ├── .editorconfig │ ├── .eslintrc.js │ ├── package.json │ ├── CHANGELOG.md │ └── README.md └── gpt-ads │ ├── .editorconfig │ ├── test │ ├── fixture │ │ ├── pages │ │ │ └── index.vue │ │ └── nuxt.config.js │ └── module.test.js │ ├── .eslintrc.js │ ├── lib │ ├── constants.js │ ├── module.js │ └── templates │ │ ├── plugin.js │ │ └── component.js │ ├── package.json │ ├── CHANGELOG.md │ └── README.md ├── lerna.json ├── package.json ├── .circleci └── config.yml ├── LICENSE ├── README.md └── .gitignore /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base", 4 | "group:allNonMajor" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /packages/dayjs/lib/constants.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | 3 | export const DEFAULT_OPTIONS = {}; 4 | -------------------------------------------------------------------------------- /packages/dayjs/lib/templates/plugin.js: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | export default async function (ctx, inject) { 4 | inject('dayjs', dayjs); 5 | } 6 | -------------------------------------------------------------------------------- /packages/dayjs/test/fixture/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | -------------------------------------------------------------------------------- /packages/lozad/lib/constants.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/prefer-default-export */ 2 | 3 | export const DEFAULT_OPTIONS = { 4 | selector: '.lozad', 5 | observer: {}, 6 | polyfill: false, 7 | }; 8 | -------------------------------------------------------------------------------- /packages/multisite/test/fixture/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 13 | -------------------------------------------------------------------------------- /packages/multisite/lib/constants.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_OPTIONS = { 2 | sites: [], 3 | debug: false, 4 | }; 5 | 6 | export const QUERY_SITE_ID_KEY = 'site'; 7 | export const COOKIE_SITE_KEY = 'site'; 8 | export const CSS_VARS_STYLE_ID = 'multisite-css-vars'; 9 | -------------------------------------------------------------------------------- /packages/dayjs/test/fixture/nuxt.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | module.exports = { 4 | rootDir: resolve(__dirname, '../..'), 5 | srcDir: __dirname, 6 | dev: false, 7 | render: { 8 | resourceHints: false, 9 | }, 10 | modules: ['@@'], 11 | }; 12 | -------------------------------------------------------------------------------- /packages/lozad/test/fixture/nuxt.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | module.exports = { 4 | rootDir: resolve(__dirname, '../..'), 5 | srcDir: __dirname, 6 | dev: false, 7 | render: { 8 | resourceHints: false, 9 | }, 10 | modules: ['@@'], 11 | }; 12 | -------------------------------------------------------------------------------- /packages/dayjs/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/gpt-ads/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/lozad/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/multisite/.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_size = 2 6 | indent_style = space 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /packages/lozad/test/fixture/pages/index.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 15 | -------------------------------------------------------------------------------- /packages/gpt-ads/test/fixture/pages/index.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "independent", 6 | "npmClient": "yarn", 7 | "conventionalCommits": true, 8 | "useWorkspaces": true, 9 | "command": { 10 | "publish": { 11 | "npmClient": "npm" 12 | } 13 | }, 14 | "ignoreChanges": [ 15 | "**/test/**", 16 | "**/*.md" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/gpt-ads/test/fixture/nuxt.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | module.exports = { 4 | rootDir: resolve(__dirname, '../..'), 5 | srcDir: __dirname, 6 | dev: false, 7 | render: { 8 | resourceHints: false, 9 | }, 10 | modules: ['@@'], 11 | gptAds: { 12 | networkCode: 6355419, 13 | individualRefresh: true, 14 | }, 15 | }; 16 | -------------------------------------------------------------------------------- /packages/dayjs/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | jest: true 10 | }, 11 | extends: 'airbnb-base', 12 | plugins: [ 13 | 'jest', 14 | 'vue' 15 | ], 16 | globals: { 17 | 'jest/globals': true, 18 | jasmine: true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/lozad/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | jest: true 10 | }, 11 | extends: 'airbnb-base', 12 | plugins: [ 13 | 'jest', 14 | 'vue' 15 | ], 16 | globals: { 17 | 'jest/globals': true, 18 | jasmine: true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/gpt-ads/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | jest: true 10 | }, 11 | extends: 'airbnb-base', 12 | plugins: [ 13 | 'jest', 14 | 'vue' 15 | ], 16 | globals: { 17 | 'jest/globals': true, 18 | jasmine: true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/multisite/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | parserOptions: { 4 | sourceType: 'module' 5 | }, 6 | env: { 7 | browser: true, 8 | node: true, 9 | jest: true 10 | }, 11 | extends: 'airbnb-base', 12 | plugins: [ 13 | 'jest', 14 | 'vue' 15 | ], 16 | globals: { 17 | 'jest/globals': true, 18 | jasmine: true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /packages/lozad/lib/templates/plugin.js: -------------------------------------------------------------------------------- 1 | import lozad from 'lozad'; 2 | <% if (options.polyfill) { %>require('intersection-observer');<% } %> 3 | 4 | export default async function (ctx, inject) { 5 | if (lozad) { 6 | const lozadOptions = [ 7 | '<%= options.selector %>', 8 | <%= JSON.stringify(options.observer) %> 9 | ] 10 | const observer = lozad(...lozadOptions); 11 | inject('lozad', observer); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /packages/gpt-ads/lib/constants.js: -------------------------------------------------------------------------------- 1 | export const DEFAULT_OPTIONS = { 2 | networkCode: null, 3 | debug: false, 4 | ghostMode: false, 5 | componentName: 'GptAd', 6 | individualRefresh: false, 7 | responsive: false, 8 | collapseEmptyDivs: false, 9 | emptyClass: 'is-empty', 10 | }; 11 | 12 | export const GPT_LIB_SCRIPT_ID = 'google-publisher-tag-lib-script'; 13 | export const GPT_INIT_SCRIPT_ID = 'google-publisher-tag-init-script'; 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ax2/nuxt-modules", 3 | "private": true, 4 | "devDependencies": { 5 | "lerna": "3.12.0" 6 | }, 7 | "scripts": { 8 | "eslint": "eslint packages/**/lib packages/**/test", 9 | "test": "jest", 10 | "release": "lerna publish" 11 | }, 12 | "jest": { 13 | "testEnvironment": "node", 14 | "coverageDirectory": "./coverage/", 15 | "collectCoverage": true 16 | }, 17 | "eslintIgnore": [ 18 | "packages/**/lib/templates/*.*" 19 | ], 20 | "workspaces": ["packages/*"] 21 | } 22 | -------------------------------------------------------------------------------- /packages/dayjs/lib/module.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_OPTIONS, 3 | } from './constants'; 4 | 5 | const { resolve } = require('path'); 6 | 7 | module.exports = async function module(moduleOptions) { 8 | const options = Object.assign(DEFAULT_OPTIONS, this.options.dayjs, moduleOptions); 9 | 10 | const templatesOptions = { 11 | ...options, 12 | }; 13 | 14 | this.addPlugin({ 15 | src: resolve(__dirname, 'templates/plugin.js'), 16 | ssr: true, 17 | fileName: 'dayjs-module/plugin.js', 18 | options: templatesOptions, 19 | }); 20 | }; 21 | module.exports.meta = require('../package.json'); 22 | -------------------------------------------------------------------------------- /packages/lozad/lib/module.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_OPTIONS, 3 | } from './constants'; 4 | 5 | const { resolve } = require('path'); 6 | 7 | module.exports = async function module(moduleOptions) { 8 | const options = Object.assign(DEFAULT_OPTIONS, this.options.lozad, moduleOptions); 9 | 10 | const templatesOptions = { 11 | ...options, 12 | }; 13 | 14 | this.addPlugin({ 15 | src: resolve(__dirname, 'templates/plugin.js'), 16 | ssr: false, 17 | fileName: 'lozad-module/plugin.js', 18 | options: templatesOptions, 19 | }); 20 | }; 21 | module.exports.meta = require('../package.json'); 22 | -------------------------------------------------------------------------------- /packages/dayjs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.1.2](https://github.com/ax2inc/nuxt-modules/compare/@ax2/dayjs-module@0.1.1...@ax2/dayjs-module@0.1.2) (2019-03-15) 7 | 8 | **Note:** Version bump only for package @ax2/dayjs-module 9 | 10 | 11 | 12 | 13 | 14 | ## 0.1.1 (2018-10-18) 15 | 16 | **Note:** Version bump only for package @ax2/dayjs-module 17 | 18 | 19 | 20 | 21 | 22 | 23 | # 0.1.0 (2018-09-18) 24 | 25 | ### Features 26 | 27 | * Initial commit 28 | -------------------------------------------------------------------------------- /packages/lozad/test/module.test.js: -------------------------------------------------------------------------------- 1 | const { Nuxt, Builder } = require('nuxt'); 2 | const request = require('request-promise-native'); 3 | 4 | const PORT = 3002; 5 | const config = require('./fixture/nuxt.config'); 6 | 7 | const url = path => `http://localhost:${PORT}${path}`; 8 | const get = path => request(url(path)); 9 | 10 | describe('basic', () => { 11 | let nuxt; 12 | 13 | beforeAll(async () => { 14 | nuxt = new Nuxt(config); 15 | await new Builder(nuxt).build(); 16 | await nuxt.listen(PORT); 17 | }, 60000); 18 | 19 | afterAll(async () => { 20 | await nuxt.close(); 21 | }); 22 | 23 | test('Render', async () => { 24 | const html = await get('/'); 25 | expect(html).toContain('Works!'); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /packages/multisite/lib/module.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_OPTIONS, 3 | QUERY_SITE_ID_KEY, 4 | COOKIE_SITE_KEY, 5 | CSS_VARS_STYLE_ID, 6 | } from './constants'; 7 | 8 | const { resolve } = require('path'); 9 | 10 | module.exports = async function module(moduleOptions) { 11 | const options = Object.assign(DEFAULT_OPTIONS, this.options.multisite, moduleOptions); 12 | 13 | const templatesOptions = { 14 | ...options, 15 | QUERY_SITE_ID_KEY, 16 | COOKIE_SITE_KEY, 17 | CSS_VARS_STYLE_ID, 18 | }; 19 | 20 | this.addPlugin({ 21 | src: resolve(__dirname, 'templates/plugin.js'), 22 | fileName: 'multisite-module/plugin.js', 23 | options: templatesOptions, 24 | }); 25 | }; 26 | module.exports.meta = require('../package.json'); 27 | -------------------------------------------------------------------------------- /packages/lozad/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.2.0](https://github.com/ax2inc/nuxt-modules/compare/@ax2/lozad-module@0.1.2...@ax2/lozad-module@0.2.0) (2020-06-03) 7 | 8 | **Note:** Version bump only for package @ax2/lozad-module 9 | 10 | 11 | 12 | 13 | 14 | ## [0.1.2](https://github.com/ax2inc/nuxt-modules/compare/@ax2/lozad-module@0.1.1...@ax2/lozad-module@0.1.2) (2019-03-15) 15 | 16 | **Note:** Version bump only for package @ax2/lozad-module 17 | 18 | 19 | 20 | 21 | 22 | ## 0.1.1 (2018-10-18) 23 | 24 | **Note:** Version bump only for package @ax2/lozad-module 25 | 26 | 27 | 28 | 29 | 30 | 31 | # 0.1.0 (2018-09-17) 32 | 33 | 34 | ### Features 35 | 36 | * Initial commit 37 | -------------------------------------------------------------------------------- /packages/gpt-ads/lib/module.js: -------------------------------------------------------------------------------- 1 | import { 2 | DEFAULT_OPTIONS, 3 | GPT_LIB_SCRIPT_ID, 4 | GPT_INIT_SCRIPT_ID, 5 | } from './constants'; 6 | 7 | const { resolve } = require('path'); 8 | 9 | module.exports = async function module(moduleOptions) { 10 | const options = Object.assign(DEFAULT_OPTIONS, this.options.gptAds, moduleOptions); 11 | 12 | const templatesOptions = { 13 | ...options, 14 | GPT_LIB_SCRIPT_ID, 15 | GPT_INIT_SCRIPT_ID, 16 | }; 17 | 18 | this.addPlugin({ 19 | src: resolve(__dirname, 'templates/plugin.js'), 20 | fileName: 'gpt-ads-module/plugin.js', 21 | options: templatesOptions, 22 | }); 23 | 24 | this.addTemplate({ 25 | src: resolve(__dirname, 'templates/component.js'), 26 | fileName: 'gpt-ads-module/component.js', 27 | options: templatesOptions, 28 | }); 29 | }; 30 | module.exports.meta = require('../package.json'); 31 | -------------------------------------------------------------------------------- /packages/dayjs/test/module.test.js: -------------------------------------------------------------------------------- 1 | const { Nuxt, Builder } = require('nuxt'); 2 | const request = require('request-promise-native'); 3 | 4 | const PORT = 3000; 5 | const config = require('./fixture/nuxt.config'); 6 | 7 | 8 | const url = path => `http://localhost:${PORT}${path}`; 9 | const get = path => request(url(path)); 10 | 11 | describe('basic', () => { 12 | let nuxt; 13 | 14 | beforeAll(async () => { 15 | nuxt = new Nuxt(config); 16 | await new Builder(nuxt).build(); 17 | await nuxt.listen(PORT); 18 | }, 60000); 19 | 20 | afterAll(async () => { 21 | await nuxt.close(); 22 | }); 23 | 24 | test('Render', async () => { 25 | const html = await get('/'); 26 | expect(html).toContain('Works!'); 27 | }); 28 | 29 | test('Formats date properly', async () => { 30 | const html = await get('/'); 31 | expect(html).toContain('Tuesday, September 18, 2018'); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | jobs: 3 | build: 4 | working_directory: /usr/src/app 5 | docker: 6 | - image: banian/node 7 | steps: 8 | # Checkout repository 9 | - checkout 10 | 11 | # Restore cache 12 | - restore_cache: 13 | key: yarn-{{ checksum "yarn.lock" }} 14 | 15 | # Install dependencies 16 | - run: 17 | name: Install Dependencies 18 | command: NODE_ENV=dev yarn 19 | 20 | # Keep cache 21 | - save_cache: 22 | key: yarn-{{ checksum "yarn.lock" }} 23 | paths: 24 | - "node_modules" 25 | 26 | # ESLint 27 | - run: 28 | name: ESLint 29 | command: yarn eslint 30 | 31 | # Test 32 | - run: 33 | name: Tests 34 | command: yarn test 35 | 36 | # Coverage 37 | - run: 38 | name: Coverage 39 | command: yarn codecov 40 | -------------------------------------------------------------------------------- /packages/gpt-ads/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ax2/gpt-ads-module", 3 | "version": "0.6.0", 4 | "description": "Google Publisher Tag ads integration for Nuxt", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "Paul Gascou-Vaillancourt " 9 | } 10 | ], 11 | "main": "lib/module.js", 12 | "repository": "https://github.com/ax2inc/nuxt-modules", 13 | "homepage": "https://github.com/ax2inc/nuxt-modules/tree/master/packages/gpt-ads#readme", 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "files": [ 18 | "lib" 19 | ], 20 | "devDependencies": { 21 | "codecov": "latest", 22 | "eslint": "5.13.0", 23 | "eslint-config-airbnb-base": "13.1.0", 24 | "eslint-loader": "2.1.2", 25 | "eslint-plugin-import": "2.16.0", 26 | "eslint-plugin-jest": "22.3.0", 27 | "eslint-plugin-vue": "5.2.1", 28 | "jest": "24.1.0", 29 | "jsdom": "14.0.0", 30 | "nuxt": "2.4.3", 31 | "request-promise-native": "1.0.5", 32 | "standard-version": "latest" 33 | }, 34 | "gitHead": "db930bf38f5eec5696ad7978a68656436831fc59" 35 | } 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Ax2 Inc. 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 | -------------------------------------------------------------------------------- /packages/dayjs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ax2/dayjs-module", 3 | "version": "0.1.2", 4 | "description": "Day.js integration for Nuxt", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "Paul Gascou-Vaillancourt " 9 | } 10 | ], 11 | "main": "lib/module.js", 12 | "repository": "https://github.com/ax2inc/nuxt-modules", 13 | "homepage": "https://github.com/ax2inc/nuxt-modules/tree/master/packages/dayjs#readme", 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "files": [ 18 | "lib" 19 | ], 20 | "dependencies": { 21 | "dayjs": "^1.7.5" 22 | }, 23 | "devDependencies": { 24 | "codecov": "latest", 25 | "eslint": "5.13.0", 26 | "eslint-config-airbnb-base": "13.1.0", 27 | "eslint-loader": "2.1.2", 28 | "eslint-plugin-import": "2.16.0", 29 | "eslint-plugin-jest": "22.3.0", 30 | "eslint-plugin-vue": "5.2.1", 31 | "jest": "24.1.0", 32 | "jsdom": "latest", 33 | "nuxt": "2.4.3", 34 | "request-promise-native": "1.0.5", 35 | "standard-version": "latest" 36 | }, 37 | "gitHead": "db930bf38f5eec5696ad7978a68656436831fc59" 38 | } 39 | -------------------------------------------------------------------------------- /packages/lozad/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ax2/lozad-module", 3 | "version": "0.2.0", 4 | "description": "Lozad integration for Nuxt", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "Paul Gascou-Vaillancourt " 9 | } 10 | ], 11 | "main": "lib/module.js", 12 | "repository": "https://github.com/ax2inc/nuxt-modules", 13 | "homepage": "https://github.com/ax2inc/nuxt-modules/tree/master/packages/lozad#readme", 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "files": [ 18 | "lib" 19 | ], 20 | "dependencies": { 21 | "intersection-observer": "^0.10.0", 22 | "lozad": "^1.15.0" 23 | }, 24 | "devDependencies": { 25 | "codecov": "latest", 26 | "eslint": "6.8.0", 27 | "eslint-config-airbnb-base": "14.1.0", 28 | "eslint-loader": "2.1.2", 29 | "eslint-plugin-import": "2.20.1", 30 | "eslint-plugin-jest": "22.3.0", 31 | "eslint-plugin-vue": "6.2.2", 32 | "jest": "26.0.1", 33 | "jsdom": "16.2.2", 34 | "nuxt": "2.12.2", 35 | "request-promise-native": "1.0.5", 36 | "standard-version": "latest" 37 | }, 38 | "gitHead": "db930bf38f5eec5696ad7978a68656436831fc59" 39 | } 40 | -------------------------------------------------------------------------------- /packages/multisite/test/fixture/nuxt.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require('path'); 2 | 3 | module.exports = { 4 | rootDir: resolve(__dirname, '../..'), 5 | srcDir: __dirname, 6 | dev: false, 7 | render: { 8 | resourceHints: false, 9 | }, 10 | modules: ['@@'], 11 | multisite: { 12 | sites: [ 13 | { 14 | id: 'my-site', 15 | title: 'My awesome site', 16 | isDefault: true, 17 | hostPatterns: 'localhost', 18 | cssVars: { 19 | '--primary-color': '#41B883', 20 | '--secondary-color': '#3B8070', 21 | }, 22 | head: { 23 | link: [ 24 | { rel: 'icon', type: 'image/x-icon', href: '/my-site/favicon.ico' }, 25 | ], 26 | }, 27 | }, 28 | { 29 | id: 'my-other-site', 30 | title: 'Another cool site', 31 | hostPatterns: '127.0.0.1', 32 | cssVars: { 33 | '--primary-color': '#fff', 34 | '--secondary-color': '#000', 35 | }, 36 | head: { 37 | link: [ 38 | { rel: 'icon', type: 'image/x-icon', href: '/my-other-site/favicon.ico' }, 39 | ], 40 | }, 41 | }, 42 | ], 43 | }, 44 | }; 45 | -------------------------------------------------------------------------------- /packages/multisite/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ax2/multisite-module", 3 | "version": "0.2.5", 4 | "description": "Multisite features for your Nuxt project", 5 | "license": "MIT", 6 | "contributors": [ 7 | { 8 | "name": "Paul Gascou-Vaillancourt " 9 | } 10 | ], 11 | "main": "lib/module.js", 12 | "repository": "https://github.com/ax2inc/nuxt-modules", 13 | "homepage": "https://github.com/ax2inc/nuxt-modules/tree/master/packages/multisite#readme", 14 | "publishConfig": { 15 | "access": "public" 16 | }, 17 | "files": [ 18 | "lib" 19 | ], 20 | "dependencies": { 21 | "cookie": "^0.3.1", 22 | "deepmerge": "2.2.1", 23 | "js-cookie": "^2.2.0" 24 | }, 25 | "devDependencies": { 26 | "codecov": "latest", 27 | "eslint": "5.13.0", 28 | "eslint-config-airbnb-base": "13.1.0", 29 | "eslint-loader": "2.1.2", 30 | "eslint-plugin-import": "2.16.0", 31 | "eslint-plugin-jest": "22.3.0", 32 | "eslint-plugin-vue": "5.2.1", 33 | "jest": "latest", 34 | "jsdom": "latest", 35 | "nuxt": "2.4.3", 36 | "request-promise-native": "1.0.5", 37 | "standard-version": "latest" 38 | }, 39 | "gitHead": "db930bf38f5eec5696ad7978a68656436831fc59" 40 | } 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

AX2's Nuxt modules

2 | 3 |

4 | 5 | 6 | AirBNB Code Style 7 | 8 | 9 | 10 | Circle CI Status 11 | 12 | 13 | 14 | 15 | Codecov Status 16 | 17 | 18 | 19 | 20 | 21 | 22 |

23 | 24 |

25 | This a monorepo containing Nuxt modules developed at Ax2.
26 | Have a look at the packages directory to see available modules. 27 |

28 | 29 | 30 |

License

31 | 32 |

33 | MIT License
34 | Copyright (c) Ax2 Inc. 35 |

36 | 37 |

38 | 39 | 40 | FOSSA Status 41 | 42 | 43 |

-------------------------------------------------------------------------------- /packages/multisite/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | ## [0.2.5](https://github.com/ax2inc/nuxt-modules/compare/@ax2/multisite-module@0.2.4...@ax2/multisite-module@0.2.5) (2019-03-15) 7 | 8 | **Note:** Version bump only for package @ax2/multisite-module 9 | 10 | 11 | 12 | 13 | 14 | ## [0.2.4](https://github.com/ax2inc/nuxt-modules/compare/@ax2/multisite-module@0.2.3...@ax2/multisite-module@0.2.4) (2019-03-15) 15 | 16 | 17 | ### Bug Fixes 18 | 19 | * Fix deepmerge call ([b612143](https://github.com/ax2inc/nuxt-modules/commit/b612143)) 20 | 21 | 22 | 23 | 24 | 25 | ## [0.2.3](https://github.com/ax2inc/nuxt-modules/compare/@ax2/multisite-module@0.2.2...@ax2/multisite-module@0.2.3) (2019-03-15) 26 | 27 | 28 | ### Bug Fixes 29 | 30 | * Fix deepmerge import ([6eebdce](https://github.com/ax2inc/nuxt-modules/commit/6eebdce)) 31 | 32 | 33 | 34 | 35 | 36 | ## [0.2.2](https://github.com/ax2inc/nuxt-modules/compare/@ax2/multisite-module@0.2.1...@ax2/multisite-module@0.2.2) (2019-03-15) 37 | 38 | 39 | ### Bug Fixes 40 | 41 | * **deps:** update dependency deepmerge to v3 ([7b7ab4a](https://github.com/ax2inc/nuxt-modules/commit/7b7ab4a)) 42 | 43 | 44 | 45 | 46 | 47 | ## 0.2.1 (2018-10-18) 48 | 49 | **Note:** Version bump only for package @ax2/multisite-module 50 | 51 | 52 | 53 | 54 | 55 | 56 | # 0.2.0 (2018-09-27) 57 | 58 | 59 | ### Features 60 | 61 | * Add debug to force usage of query string when needed 62 | 63 | 64 | ## 0.1.1 (2018-09-15) 65 | 66 | 67 | ### Bug Fixes 68 | 69 | * Merge head properties using deepmerge 70 | 71 | 72 | 73 | # 0.1.0 (2018-09-08) 74 | 75 | 76 | ### Features 77 | 78 | * Initial commit 79 | -------------------------------------------------------------------------------- /packages/dayjs/README.md: -------------------------------------------------------------------------------- 1 | # dayjs-module 2 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@ax2/dayjs-module/latest.svg?style=flat-square)](https://npmjs.com/package/@ax2/dayjs-module) 3 | [![npm](https://img.shields.io/npm/dt/@ax2/dayjs-module.svg?style=flat-square)](https://npmjs.com/package/@ax2/dayjs-module) 4 | [![Dependencies](https://david-dm.org/ax2inc/dayjs-module/status.svg?style=flat-square)](https://david-dm.org/ax2inc/dayjs-module) 5 | [![Code Style](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript) 6 | 7 | > Day.js integration for Nuxt 8 | 9 | [📖 **Release Notes**](./CHANGELOG.md) 10 | 11 | ## Features 12 | 13 | Integrate [Day.js](https://github.com/iamkun/dayjs) with your Nuxt project. 14 | 15 | ## Setup 16 | 17 | - Install the module with your favorite package manager. 18 | 19 | ```sh 20 | yarn add @ax2/dayjs-module 21 | # Or npm i @ax2/dayjs-module 22 | ``` 23 | 24 | - Add `dayjs-module` to `modules` section of `nuxt.config.js`. 25 | 26 | ```js 27 | // nuxt.config.js 28 | 29 | { 30 | modules: [ 31 | '@ax2/dayjs-module', 32 | ], 33 | } 34 | ``` 35 | 36 | - Configure the module as needed by adding a `dayjs` key to `nuxt.config.js`. 37 | 38 | ```js 39 | // nuxt.config.js 40 | 41 | { 42 | dayjs: { 43 | // Module options 44 | } 45 | } 46 | ``` 47 | 48 | ## Usage 49 | 50 | At the moment, all the module does is inject Day.js into Vue instances so you can call it from anywhere in your app: 51 | 52 | ```vue 53 | 59 | ``` 60 | 61 | ## Development 62 | 63 | - Clone this repository 64 | - Install dependencies using `yarn install` or `npm install` 65 | - Start development server using `npm run dev` 66 | 67 | ## License 68 | 69 | [MIT License](../../LICENSE) 70 | 71 | Copyright (c) Ax2 Inc. 72 | -------------------------------------------------------------------------------- /packages/gpt-ads/test/module.test.js: -------------------------------------------------------------------------------- 1 | const { Nuxt, Builder } = require('nuxt'); 2 | const jsdom = require('jsdom'); 3 | const request = require('request-promise-native'); 4 | 5 | const PORT = 3001; 6 | const config = require('./fixture/nuxt.config'); 7 | 8 | const { JSDOM } = jsdom; 9 | const getDom = html => (new JSDOM(html)).window.document; 10 | 11 | const url = path => `http://localhost:${PORT}${path}`; 12 | const get = path => request(url(path)); 13 | 14 | const GPT_LIB_SCRIPT_ID = 'google-publisher-tag-lib-script'; 15 | const GPT_INIT_SCRIPT_ID = 'google-publisher-tag-init-script'; 16 | 17 | describe('basic', () => { 18 | let nuxt; 19 | 20 | beforeAll(async () => { 21 | nuxt = new Nuxt(config); 22 | await new Builder(nuxt).build(); 23 | await nuxt.listen(PORT); 24 | }, 60000); 25 | 26 | afterAll(async () => { 27 | await nuxt.close(); 28 | }); 29 | 30 | test('Render', async () => { 31 | const html = await get('/'); 32 | expect(html).toContain('Works!'); 33 | }); 34 | 35 | test('Injects Google Publisher Tag lib', async () => { 36 | const html = await get('/'); 37 | const dom = getDom(html); 38 | const node = dom.querySelector(`head #${GPT_LIB_SCRIPT_ID}`); 39 | expect(node.src).toBe('https://www.googletagservices.com/tag/js/gpt.js'); 40 | }); 41 | 42 | test('Injects Google Publisher Tag init script', async () => { 43 | const html = await get('/'); 44 | const dom = getDom(html); 45 | const node = dom.querySelector(`head #${GPT_INIT_SCRIPT_ID}`); 46 | expect(node).not.toBeNull(); 47 | }); 48 | 49 | test('Properly handles individualRefresh option', async () => { 50 | const html = await get('/'); 51 | expect(html).toContain('googletag.pubads().disableInitialLoad();'); 52 | }); 53 | 54 | test('Renders a div for the ad', async () => { 55 | const html = await get('/'); 56 | const dom = getDom(html); 57 | const node = dom.querySelector('#ad-container > div'); 58 | expect(node).not.toBeNull(); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /packages/gpt-ads/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. 5 | 6 | # [0.6.0](https://github.com/ax2inc/nuxt-modules/compare/@ax2/gpt-ads-module@0.5.3...@ax2/gpt-ads-module@0.6.0) (2019-03-15) 7 | 8 | 9 | ### Features 10 | 11 | * Toggle class on ads slots when they become empty ([a3863f1](https://github.com/ax2inc/nuxt-modules/commit/a3863f1)) 12 | 13 | 14 | 15 | 16 | 17 | ## [0.5.3](https://github.com/ax2inc/nuxt-modules/compare/@ax2/gpt-ads-module@0.5.2...@ax2/gpt-ads-module@0.5.3) (2018-11-01) 18 | 19 | 20 | ### Bug Fixes 21 | 22 | * Test window.googletag rather than googletag, prevents an error in SPA mode ([38699d7](https://github.com/ax2inc/nuxt-modules/commit/38699d7)) 23 | 24 | 25 | 26 | 27 | 28 | ## 0.5.2 (2018-10-18) 29 | 30 | **Note:** Version bump only for package @ax2/gpt-ads-module 31 | 32 | 33 | 34 | 35 | 36 | 37 | ## 0.5.1 (2018-10-11) 38 | 39 | 40 | ### Bug Fixes 41 | 42 | * Prevent error with size mappings that have a single size definition 43 | 44 | 45 | # 0.5.0 (2018-10-11) 46 | 47 | 48 | ### Features 49 | 50 | * Add ghostMode option 51 | 52 | 53 | ## 0.4.1 (2018-10-05) 54 | 55 | 56 | ### Bug Fixes 57 | 58 | * Rely on self-built sizes mapping 59 | 60 | 61 | # 0.4.0 (2018-10-04) 62 | 63 | 64 | ### Bug Fixes 65 | 66 | * Prevent TypeError if mapping were to be undefined 67 | 68 | 69 | ### Features 70 | 71 | * Add collapseEmptyDivs option & collapseEmptyDiv prop 72 | 73 | 74 | # 0.3.0 (2018-10-04) 75 | 76 | 77 | ### Features 78 | 79 | * Add responsive option and isResponsive prop 80 | 81 | 82 | # 0.2.0 (2018-09-27) 83 | 84 | 85 | ### Features 86 | 87 | * Add individualRefresh option 88 | 89 | 90 | ## 0.1.1 (2018-09-26) 91 | 92 | 93 | ### Bug Fixes 94 | 95 | * Slot size should be treated as a list 96 | 97 | 98 | # 0.1.0 (2018-09-11) 99 | 100 | 101 | ### Features 102 | 103 | * Initial commit 104 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## macOS.gitignore 2 | ## https://github.com/github/gitignore/blob/master/Global/macOS.gitignore 3 | 4 | # General 5 | .DS_Store 6 | .AppleDouble 7 | .LSOverride 8 | 9 | # Icon must end with two \r 10 | Icon 11 | 12 | 13 | # Thumbnails 14 | ._* 15 | 16 | # Files that might appear in the root of a volume 17 | .DocumentRevisions-V100 18 | .fseventsd 19 | .Spotlight-V100 20 | .TemporaryItems 21 | .Trashes 22 | .VolumeIcon.icns 23 | .com.apple.timemachine.donotpresent 24 | 25 | # Directories potentially created on remote AFP share 26 | .AppleDB 27 | .AppleDesktop 28 | Network Trash Folder 29 | Temporary Items 30 | .apdisk 31 | 32 | 33 | ## Node.gitignore 34 | ## https://github.com/github/gitignore/blob/master/Node.gitignore 35 | 36 | # Logs 37 | logs 38 | *.log 39 | npm-debug.log* 40 | yarn-debug.log* 41 | yarn-error.log* 42 | 43 | # Runtime data 44 | pids 45 | *.pid 46 | *.seed 47 | *.pid.lock 48 | 49 | # Directory for instrumented libs generated by jscoverage/JSCover 50 | lib-cov 51 | 52 | # Coverage directory used by tools like istanbul 53 | coverage 54 | 55 | # nyc test coverage 56 | .nyc_output 57 | 58 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 59 | .grunt 60 | 61 | # Bower dependency directory (https://bower.io/) 62 | bower_components 63 | 64 | # node-waf configuration 65 | .lock-wscript 66 | 67 | # Compiled binary addons (https://nodejs.org/api/addons.html) 68 | build/Release 69 | 70 | # Dependency directories 71 | node_modules/ 72 | jspm_packages/ 73 | 74 | # TypeScript v1 declaration files 75 | typings/ 76 | 77 | # Optional npm cache directory 78 | .npm 79 | 80 | # Optional eslint cache 81 | .eslintcache 82 | 83 | # Optional REPL history 84 | .node_repl_history 85 | 86 | # Output of 'npm pack' 87 | *.tgz 88 | 89 | # Yarn Integrity file 90 | .yarn-integrity 91 | 92 | # dotenv environment variables file 93 | .env 94 | 95 | # parcel-bundler cache (https://parceljs.org/) 96 | .cache 97 | 98 | # next.js build output 99 | .next 100 | 101 | # nuxt.js build output 102 | .nuxt 103 | 104 | # vuepress build output 105 | .vuepress/dist 106 | 107 | # Serverless directories 108 | .serverless -------------------------------------------------------------------------------- /packages/gpt-ads/lib/templates/plugin.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | export default async function (ctx, inject) { 4 | 5 | const { app } = ctx; 6 | 7 | // Module options 8 | const debug = <%= options.debug || false %>; 9 | const individualRefresh = <%= options.individualRefresh || false %>; 10 | const collapseEmptyDivs = <%= options.collapseEmptyDivs || false %>; 11 | const networkCode = '<%= options.networkCode %>'; 12 | const GPT_LIB_SCRIPT_ID = '<%= options.GPT_LIB_SCRIPT_ID %>'; 13 | const GPT_INIT_SCRIPT_ID = '<%= options.GPT_INIT_SCRIPT_ID %>'; 14 | 15 | // Instance options 16 | const gptAdsOptions = { 17 | networkCode, 18 | individualRefresh, 19 | slots: [], 20 | }; 21 | 22 | const injectScript = (script) => { 23 | const scriptIndex = ctx.app.head.script.findIndex(s => s.id === script.id); 24 | if (scriptIndex !== -1) { 25 | ctx.app.head.script[scriptIndex] = script; 26 | } else { 27 | ctx.app.head.script.push(script); 28 | } 29 | }; 30 | 31 | // Inject GPT lib 32 | const gptLibScript = { 33 | id: GPT_LIB_SCRIPT_ID, 34 | src: 'https://www.googletagservices.com/tag/js/gpt.js', 35 | async: true, 36 | }; 37 | injectScript(gptLibScript); 38 | 39 | // Inject GPT init script 40 | let gptInitScriptHtml = 'var googletag = googletag || {};googletag.cmd = googletag.cmd || [];'; 41 | if (debug) { 42 | gptInitScriptHtml += 'googletag.cmd.push(function(){googletag.openConsole();});'; 43 | } 44 | // Disable initial load 45 | const gptDisableInitialLoad = individualRefresh ? 'googletag.pubads().disableInitialLoad();' : ''; 46 | // Collapse empty div 47 | const gptCollapseEmptyDivs = collapseEmptyDivs ? 'googletag.pubads().collapseEmptyDivs();' : ''; 48 | 49 | gptInitScriptHtml += ` 50 | googletag.cmd.push(function(){ 51 | googletag.pubads().enableSingleRequest(); 52 | ${gptDisableInitialLoad} 53 | ${gptCollapseEmptyDivs} 54 | googletag.enableServices(); 55 | }); 56 | `; 57 | const gptInitScript = { 58 | id: GPT_INIT_SCRIPT_ID, 59 | innerHTML: gptInitScriptHtml, 60 | }; 61 | injectScript(gptInitScript); 62 | 63 | const component = require('./component.js'); 64 | Vue.component('<%= options.componentName %>', component.default || component); 65 | 66 | inject('gptAds', gptAdsOptions); 67 | } 68 | -------------------------------------------------------------------------------- /packages/lozad/README.md: -------------------------------------------------------------------------------- 1 | # lozad-module 2 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@ax2/lozad-module/latest.svg?style=flat-square)](https://npmjs.com/package/@ax2/lozad-module) 3 | [![npm](https://img.shields.io/npm/dt/@ax2/lozad-module.svg?style=flat-square)](https://npmjs.com/package/@ax2/lozad-module) 4 | [![Dependencies](https://david-dm.org/ax2inc/lozad-module/status.svg?style=flat-square)](https://david-dm.org/ax2inc/lozad-module) 5 | [![Code Style](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript) 6 | 7 | > Lozad.js integration for Nuxt 8 | 9 | [📖 **Release Notes**](./CHANGELOG.md) 10 | 11 | ## Features 12 | 13 | Integrate [Lozad.js](https://github.com/ApoorvSaxena/lozad.js) with your Nuxt project. 14 | 15 | ## Setup 16 | 17 | - Install the module with your favorite package manager. 18 | 19 | ```sh 20 | yarn add @ax2/lozad-module 21 | # Or npm i @ax2/lozad-module 22 | ``` 23 | 24 | - Add `lozad-module` to `modules` section of `nuxt.config.js`. 25 | 26 | ```js 27 | // nuxt.config.js 28 | 29 | { 30 | modules: [ 31 | '@ax2/lozad-module', 32 | ], 33 | } 34 | ``` 35 | 36 | - Configure the module as needed by adding a `lozad` key to `nuxt.config.js`. 37 | 38 | ```js 39 | // nuxt.config.js 40 | 41 | { 42 | lozad: { 43 | // Module options 44 | } 45 | } 46 | ``` 47 | 48 | ## Options 49 | 50 | ### selector 51 | 52 | - **Type**: `String` 53 | - **Default**: `'.lozad'` 54 | 55 | Selector which lozad uses to find elements to be lazy-loaded. 56 | 57 | ### observer 58 | 59 | - **Type**: `Object` 60 | - **Default**: `{}` 61 | 62 | IntersectionObserver options, see [lozad options](https://apoorv.pro/lozad.js/#usage). 63 | 64 | ### polyfill 65 | 66 | - **Type**: `Boolean` 67 | - **Default**: `false` 68 | 69 | Set to `true` to enable [IntersectionObserver](https://caniuse.com/#feat=intersectionobserver) polyfill. 70 | 71 | ## Usage 72 | 73 | To enable lazy-loading, you must trigger lozad's `observe()` method in the `mounted()` hook of your pages/components that include lazy-loadable content. 74 | 75 | ```vue 76 | 81 | 82 | 89 | 90 | ``` 91 | 92 | 93 | ## Development 94 | 95 | - Clone this repository 96 | - Install dependencies using `yarn install` or `npm install` 97 | - Start development server using `npm run dev` 98 | 99 | ## License 100 | 101 | [MIT License](../../LICENSE) 102 | 103 | Copyright (c) Ax2 Inc. 104 | -------------------------------------------------------------------------------- /packages/multisite/test/module.test.js: -------------------------------------------------------------------------------- 1 | const { Nuxt, Builder } = require('nuxt'); 2 | const jsdom = require('jsdom'); 3 | const request = require('request-promise-native'); 4 | 5 | const PORT = 3003; 6 | const config = require('./fixture/nuxt.config'); 7 | 8 | const { JSDOM } = jsdom; 9 | const getDom = html => (new JSDOM(html)).window.document; 10 | 11 | const url = path => `http://localhost:${PORT}${path}`; 12 | const get = path => request(url(path)); 13 | const getComputedCssVars = (cssVars) => { 14 | const style = Object.keys(cssVars).map(key => `${key}:${cssVars[key]}`); 15 | return `:root{${style.join(';')}}`; 16 | }; 17 | 18 | describe('basic', () => { 19 | let nuxt; 20 | 21 | beforeAll(async () => { 22 | nuxt = new Nuxt(config); 23 | await new Builder(nuxt).build(); 24 | await nuxt.listen(PORT); 25 | }, 60000); 26 | 27 | afterAll(async () => { 28 | await nuxt.close(); 29 | }); 30 | 31 | test('Render', async () => { 32 | const html = await get('/'); 33 | expect(html).toContain('Works!'); 34 | }); 35 | 36 | /** 37 | * localhost 38 | */ 39 | describe(`localhost - ${config.multisite.sites[0].id}`, () => { 40 | const siteUrl = path => `http://localhost:${PORT}${path}`; 41 | const siteGet = path => request(siteUrl(path)); 42 | 43 | test('Enables proper site', async () => { 44 | const html = await siteGet('/'); 45 | expect(html).toContain('My awesome site'); 46 | }); 47 | 48 | test('Sets proper css vars', async () => { 49 | const html = await siteGet('/'); 50 | const dom = getDom(html); 51 | const node = dom.querySelector('#multisite-css-vars'); 52 | expect(node.textContent).toBe(getComputedCssVars(config.multisite.sites[0].cssVars)); 53 | }); 54 | 55 | test('Uses proper favicon', async () => { 56 | const html = await request(`http://localhost:${PORT}/`); 57 | const dom = getDom(html); 58 | const node = dom.querySelector('link[rel="icon"]'); 59 | expect(node.href).toBe(config.multisite.sites[0].head.link[0].href); 60 | }); 61 | }); 62 | 63 | /** 64 | * 127.0.0.1 65 | */ 66 | describe(`127.0.0.1 - ${config.multisite.sites[1].id}`, () => { 67 | const siteUrl = path => `http://127.0.0.1:${PORT}${path}`; 68 | const siteGet = path => request(siteUrl(path)); 69 | 70 | test('Enables proper site', async () => { 71 | const html = await siteGet('/'); 72 | expect(html).toContain('Another cool site'); 73 | }); 74 | 75 | test('Sets proper css vars', async () => { 76 | const html = await siteGet('/'); 77 | const dom = getDom(html); 78 | const node = dom.querySelector('#multisite-css-vars'); 79 | expect(node.textContent).toBe(getComputedCssVars(config.multisite.sites[1].cssVars)); 80 | }); 81 | 82 | test('Uses proper favicon', async () => { 83 | const html = await siteGet('/'); 84 | const dom = getDom(html); 85 | const node = dom.querySelector('link[rel="icon"]'); 86 | expect(node.href).toBe(config.multisite.sites[1].head.link[0].href); 87 | }); 88 | }); 89 | }); 90 | -------------------------------------------------------------------------------- /packages/multisite/lib/templates/plugin.js: -------------------------------------------------------------------------------- 1 | import Cookies from 'js-cookie'; 2 | import cookie from 'cookie'; 3 | import deepmerge from 'deepmerge'; 4 | 5 | export default (ctx, inject) => { 6 | const { 7 | req, 8 | res, 9 | query, 10 | isDev, 11 | } = ctx; 12 | 13 | // Module options 14 | const sites = <%= JSON.stringify(options.sites) %>; 15 | const debug = <%= options.debug %>; 16 | const QUERY_SITE_ID_KEY = '<%= options.QUERY_SITE_ID_KEY %>'; 17 | const COOKIE_SITE_KEY = '<%= options.COOKIE_SITE_KEY %>'; 18 | const CSS_VARS_STYLE_ID = '<%= options.CSS_VARS_STYLE_ID %>'; 19 | const defaultSite = sites.find(site => site.isDefault); 20 | 21 | // Instance options 22 | const multisiteOptions = { 23 | site: null, 24 | }; 25 | 26 | // Guess current site 27 | let currentSiteId = null; 28 | // In development, get current site from cookies or query string 29 | if (debug || isDev) { 30 | currentSiteId = query[QUERY_SITE_ID_KEY]; 31 | 32 | // If no site ID found in query string, attempt to retrieve it from cookies 33 | if (!currentSiteId) { 34 | if (process.server) { 35 | const cookies = cookie.parse(req.headers.cookie || ''); 36 | currentSiteId = cookies[COOKIE_SITE_KEY] || null; 37 | } else { 38 | currentSiteId = Cookies.get(COOKIE_SITE_KEY) || null; 39 | } 40 | } 41 | 42 | // Set cookie 43 | if (currentSiteId && process.server) { 44 | res.setHeader('Set-Cookie', cookie.serialize(COOKIE_SITE_KEY, String(currentSiteId), { 45 | httpOnly: false, 46 | path: '/', 47 | maxAge: 60 * 60 * 24 * 365, // 1 year 48 | })); 49 | } 50 | } else { 51 | // Get current site from request or location 52 | const { host } = process.server ? req.headers : window.location; 53 | sites.some((site) => { 54 | let patterns = site.hostPatterns || null; 55 | if (patterns) { 56 | patterns = patterns.split(','); 57 | return patterns.some((pattern) => { 58 | const regexp = new RegExp(pattern); 59 | if (regexp.test(host)) { 60 | currentSiteId = site.id; 61 | return true; 62 | } 63 | }); 64 | } 65 | }); 66 | } 67 | 68 | const currentSite = currentSiteId ? sites.find(site => site.id === currentSiteId) : defaultSite; 69 | 70 | multisiteOptions.site = currentSite; 71 | 72 | // CSS vars 73 | const getComputedCssVars = (cssVars) => { 74 | const style = Object.keys(cssVars).map(key => `${key}:${cssVars[key]}`); 75 | return `:root{${style.join(';')}}`; 76 | }; 77 | const headStyle = { 78 | id: CSS_VARS_STYLE_ID, 79 | type: 'text/css', 80 | innerHTML: getComputedCssVars(currentSite.cssVars), 81 | }; 82 | const styleIndex = ctx.app.head.style.findIndex(style => style.id === CSS_VARS_STYLE_ID); 83 | if (styleIndex !== -1) { 84 | ctx.app.head.style[styleIndex] = headStyle; 85 | } else { 86 | ctx.app.head.style.push(headStyle); 87 | } 88 | 89 | // Meta 90 | if (typeof currentSite.head !== 'undefined') { 91 | ctx.app.head = deepmerge(ctx.app.head, currentSite.head); 92 | } 93 | 94 | // Assets helper 95 | multisiteOptions.asset = (path, site = null) => { 96 | site = site || currentSite.id; 97 | return `/${site}/${path}`; 98 | }; 99 | 100 | inject('multisite', multisiteOptions); 101 | }; 102 | -------------------------------------------------------------------------------- /packages/multisite/README.md: -------------------------------------------------------------------------------- 1 | # multisite-module 2 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@ax2/multisite-module/latest.svg?style=flat-square)](https://npmjs.com/package/@ax2/multisite-module) 3 | [![npm](https://img.shields.io/npm/dt/@ax2/multisite-module.svg?style=flat-square)](https://npmjs.com/package/@ax2/multisite-module) 4 | [![Dependencies](https://david-dm.org/ax2inc/multisite-module/status.svg?style=flat-square)](https://david-dm.org/ax2inc/multisite-module) 5 | [![Code Style](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript) 6 | 7 | 8 | > Multisite features for your Nuxt project 9 | 10 | [📖 **Release Notes**](./CHANGELOG.md) 11 | 12 | ## Features 13 | 14 | This module helps you bring multisite features to your Nuxt project. Here are the main features: 15 | 16 | - Current site detection based on host (or query string in development) 17 | - Contextual CSS vars declaration for site-specific theming 18 | - Contextual meta data 19 | 20 | ## Setup 21 | 22 | - Install the module with your favorite package manager. 23 | 24 | ```sh 25 | yarn add @ax2/multisite-module 26 | # Or npm i @ax2/multisite-module 27 | ``` 28 | 29 | - Add `@ax2/multisite-module` to `modules` section of `nuxt.config.js`. 30 | 31 | ```js 32 | // nuxt.config.js 33 | 34 | { 35 | modules: [ 36 | '@ax2/multisite-module', 37 | ], 38 | } 39 | ``` 40 | 41 | - Configure the module as needed by adding a `multisite` key to `nuxt.config.js`. 42 | 43 | ```js 44 | // nuxt.config.js 45 | 46 | { 47 | multisite: { 48 | // Module options 49 | } 50 | } 51 | ``` 52 | 53 | 54 | ## Options 55 | 56 | ### debug 57 | 58 | - Type: `Boolean` 59 | - **Default**: `false` 60 | 61 | Set this to `true` to force the module to get the current site from the query string. 62 | 63 | ### sites 64 | 65 | - Type: `Array` 66 | 67 | List of sites. 68 | 69 | ```js 70 | { 71 | multisite: { 72 | sites: [ 73 | { 74 | id: 'my-site', 75 | title: 'My awesome site', 76 | isDefault: true, 77 | hostPatterns: 'myawesomesite\.com,myincrediblesite\.(com|org)', 78 | cssVars: { 79 | '--primary-color': '#41B883', 80 | '--secondary-color': '#3B8070', 81 | }, 82 | head: { 83 | link: [ 84 | { rel: 'icon', type: 'image/x-icon', href: '/my-site/favicon.ico' }, 85 | ], 86 | }, 87 | }, 88 | ], 89 | }, 90 | } 91 | ``` 92 | 93 | Each item in `sites` can have a few options of its own: 94 | 95 | #### id 96 | 97 | - Type: `Integer|String` 98 | 99 | The site's unique identifier. 100 | 101 | #### isDefault 102 | 103 | - Type: `Boolean` 104 | 105 | Wether this site should be considered as the default one. Any request that cannot be resolved to one of the sites will fallback to the default one. 106 | 107 | #### hostPatterns 108 | 109 | - Type: `String` 110 | 111 | A list of comma-separated patterns to test against requests host in order to enable this site in production. 112 | 113 | #### cssVars 114 | 115 | - Type: `Object` 116 | 117 | CSS vars that should be set when visiting this site. 118 | 119 | #### head 120 | 121 | - Type: `Object` 122 | 123 | This is the same as Nuxt's [head property](https://nuxtjs.org/api/configuration-head#the-head-property), options defined here are merged with the main `head` property definition. 124 | 125 | > NOTE: Functions are not supported here 126 | 127 | ## Usage 128 | 129 | ### Development 130 | 131 | In development, switch from one site to another by adding a `site` query parameter to the URL. The value should be the site's ID as defined in the module's configuration. ie: [http://127.0.0.1:8080/?site=my-site](http://127.0.0.1:8080/?site=my-site) 132 | 133 | Active site is stored in a cookie, so next time you visit [http://127.0.0.1:8080](http://127.0.0.1:8080), active site will be last used one. 134 | 135 | ### Production 136 | 137 | In production, active site is detected by matching request host against the patterns you defined in `hostPatterns` options. ie if you visit [http://myawesomesite.com](http://myawesomesite.com), `my-site` will be set as active site. 138 | 139 | A `$multisite` property is added to the app's context, it contains a few helpers that you can use in any component. 140 | 141 | ### Properties 142 | 143 | #### site 144 | 145 | - Type: `Object` 146 | 147 | The `site` property contains current site's configuration. You could use it to display the current site's title: 148 | 149 | ```vue 150 | 155 | ``` 156 | 157 | ### Methods 158 | 159 | #### asset 160 | 161 | - Arguments 162 | - `{String} path`: required 163 | - `{Integer|String} site`: optional, defaults to current site ID 164 | - Return: `String` 165 | 166 | Get an asset's path for given site. If no site is specified, defaults to active site. 167 | 168 | ```vue 169 | 175 | ``` 176 | 177 | > NOTE: It's recommended that you place site-specific assets in a directory named after the site's ID as defined in the module's options. Sites assets directories should be in the static/ directory. 178 | 179 | ## License 180 | 181 | [MIT License](../../LICENSE) 182 | 183 | Copyright (c) Ax2 Inc. 184 | -------------------------------------------------------------------------------- /packages/gpt-ads/README.md: -------------------------------------------------------------------------------- 1 | # gpt-ads-module 2 | [![npm (scoped with tag)](https://img.shields.io/npm/v/@ax2/gpt-ads-module/latest.svg?style=flat-square)](https://npmjs.com/package/@ax2/gpt-ads-module) 3 | [![npm](https://img.shields.io/npm/dt/@ax2/gpt-ads-module.svg?style=flat-square)](https://npmjs.com/package/@ax2/gpt-ads-module) 4 | [![Dependencies](https://david-dm.org/ax2inc/gpt-ads-module/status.svg?style=flat-square)](https://david-dm.org/ax2inc/gpt-ads-module) 5 | [![Code Style](https://badgen.net/badge/code%20style/airbnb/ff5a5f?icon=airbnb)](https://github.com/airbnb/javascript) 6 | 7 | > Google Publisher Tag ads integration for Nuxt 8 | 9 | [📖 **Release Notes**](./CHANGELOG.md) 10 | 11 | ## Features 12 | 13 | Integrate Google Publisher Tag with your Nuxt project. 14 | 15 | ## Setup 16 | 17 | - Install the module with your favorite package manager. 18 | 19 | ```sh 20 | yarn add @ax2/gpt-ads-module 21 | # Or npm i @ax2/gpt-ads-module 22 | ``` 23 | 24 | - Add `@ax2/gpt-ads-module` to `modules` section of `nuxt.config.js`. 25 | 26 | ```js 27 | // nuxt.config.js 28 | 29 | { 30 | modules: [ 31 | '@ax2/gpt-ads-module', 32 | ], 33 | } 34 | ``` 35 | 36 | - Configure the module as needed by adding a `gptAds` key to `nuxt.config.js`. 37 | 38 | ```js 39 | // nuxt.config.js 40 | 41 | { 42 | gptAds: { 43 | // Module options 44 | } 45 | } 46 | ``` 47 | 48 | ## Options 49 | 50 | ### networkCode 51 | 52 | - **Type**: `Array|String`: required 53 | 54 | Your network code as found in **Google Ad Manager > Admin > Global Settings**. 55 | 56 | ### debug 57 | 58 | - **Type**: `Boolean` 59 | - **Default**: `false` 60 | 61 | Enable debug mode, when this is `true`, GPT console opens when the app loads. 62 | 63 | ### componentName 64 | 65 | - **Type**: `String` 66 | - **Default**: `'GptAd'` 67 | 68 | Name of the component that the module registers. 69 | 70 | ### individualRefresh 71 | 72 | - **Type**: `Boolean` 73 | - **Default**: `false` 74 | 75 | If enabled, ads won't be fetched on page load but will be refreshed individually as they are mounted. 76 | 77 | ### responsive 78 | 79 | - **Type**: `Boolean` 80 | - **Default**: `false` 81 | 82 | Set to `true` to enable responsive mode for all ads slot. In responsive mode, ad slots listen to window resize events and refresh themselves if a different size mapping matches current window size. 83 | 84 | ### collapseEmptyDivs 85 | 86 | - **Type**: `Boolean` 87 | - **Default**: `false` 88 | 89 | Set to `true` to have empty ad slots collapsed themselves, this can be overridden at slot-level with `collapseEmptyDiv` prop. 90 | 91 | ### ghostMode 92 | 93 | - **Type**: `Boolean` 94 | - **Default**: `false` 95 | 96 | Set to `true` to enable ghost mode. With ghost mode enabled, ad slots aren't displayed and are replaced by empty bordered divs of the size the ads would have if they were displayed. This is useful during development where you might not want to display real ads. 97 | 98 | ### emptyClass 99 | 100 | - **Type**: `String` 101 | - **Default**: `'is-empty'` 102 | 103 | Class to apply to empty ads slots. 104 | 105 | ## Usage 106 | 107 | When the module is enabled, it registers a global Vue component that you can use to display ads in your app. By default, the component's name is **GptAd** but this can be changed via the `componentName` option. 108 | 109 | The component accepts a few props to customize the ads you display. 110 | 111 | ### Props 112 | 113 | #### adUnit 114 | 115 | - Type: `string`: required 116 | 117 | The ad unit for a given ad as defined in Google Ad Manager > Inventory > Ad units. 118 | 119 | #### size 120 | 121 | - Type: `Array|string`: required 122 | 123 | Default size for this ad, can be an array (`[, ]`) or a string (`'x'`). 124 | 125 | To support multiple sizes, either pass an array of arrays (`[[, ], [, ]]`), or a string where dimensions are separated by a comma (`'x,x'`). 126 | 127 | #### sizeMapping 128 | 129 | - Type: `Array` 130 | - Default: `[]` 131 | 132 | Size mapping for this ad. Each item in the list is an array of its own, where the first item is the browser size, and the second is the expected ad's size(s) for the breakpoint. 133 | Sizes should either be arrays in the form `[, ]` or strings in the form `'x'`. 134 | 135 | #### isResponsive 136 | 137 | - Type: `Boolean` 138 | - Default: `<%= options.responsive %>` 139 | 140 | Turn responsive mode on or off for specific ads, defaults to module's `responsive` option. 141 | 142 | #### windowResizeDebounce 143 | 144 | - Type: `Number` 145 | - Default: `300` 146 | 147 | Debounce duration between each window resize handling. 148 | 149 | #### collapseEmptyDiv 150 | 151 | - Type: `Boolean` 152 | - Default: `null` 153 | 154 | Override `collapseEmptyDivs` option at the slot's level. 155 | 156 | ### Examples 157 | 158 | 159 | ```vue 160 | 171 | ``` 172 | 173 | Equivalent: 174 | 175 | 176 | ```vue 177 | 188 | ``` 189 | 190 | 191 | ## Development 192 | 193 | - Clone this repository 194 | - Install dependencies using `yarn install` or `npm install` 195 | - Start development server using `npm run dev` 196 | 197 | ## License 198 | 199 | [MIT License](../../LICENSE) 200 | 201 | Copyright (c) Ax2 Inc. 202 | -------------------------------------------------------------------------------- /packages/gpt-ads/lib/templates/component.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: '<%= options.componentName %>', 3 | data: () => ({ 4 | adSlot: null, 5 | mapping: [], 6 | currentSizeMappingIndex: null, 7 | windowResizeListenerDebounce: null, 8 | ghostMode: <%= options.ghostMode %>, 9 | isEmpty: true, 10 | }), 11 | props: { 12 | adUnit: { 13 | type: String, 14 | required: true, 15 | }, 16 | size: { 17 | type: [Array, String], 18 | required: true, 19 | }, 20 | sizeMapping: { 21 | type: Array, 22 | required: false, 23 | default: () => [], 24 | }, 25 | id: { 26 | type: [Number, String], 27 | required: false, 28 | default: () => Math.random().toString(36).substring(5), 29 | }, 30 | isResponsive: { 31 | type: Boolean, 32 | required: false, 33 | default: <%= options.responsive %>, 34 | }, 35 | windowResizeDebounce: { 36 | type: Number, 37 | required: false, 38 | default: 300, 39 | }, 40 | collapseEmptyDiv: { 41 | type: Boolean, 42 | required: false, 43 | default: null, 44 | }, 45 | }, 46 | computed: { 47 | networkCode() { 48 | const { $gptAds } = this; 49 | return $gptAds ? $gptAds.networkCode : null; 50 | }, 51 | adUnitPath() { 52 | const { networkCode, adUnit } = this; 53 | return `/${networkCode}/${adUnit}`; 54 | }, 55 | divId() { 56 | const { id } = this; 57 | return `div-gpt-ad-${id}-0`; 58 | }, 59 | formattedSize() { 60 | return this.formatSizeList(this.size); 61 | }, 62 | style() { 63 | if (this.ghostMode) { 64 | const { formattedSize, currentSizeMappingIndex, mapping } = this; 65 | let baseSize = formattedSize; 66 | if (currentSizeMappingIndex !== null) { 67 | baseSize = mapping[currentSizeMappingIndex][1]; 68 | } 69 | const size = Array.isArray(baseSize[0]) ? baseSize[0] : [baseSize[0], baseSize[1]]; 70 | const [width, height] = size; 71 | return { 72 | margin: '0 auto', 73 | width: `${width}px`, 74 | height: `${height}px`, 75 | border: '1px solid black', 76 | }; 77 | } 78 | return null; 79 | }, 80 | }, 81 | methods: { 82 | /** 83 | * Formats a given size to make it compatible with GPT 84 | * If size is an Array, it is returned as is 85 | * If size is a string, it is formatted so that 123x456 becomes [123, 456] 86 | * 87 | * @param {Array,string} size The size 88 | * @return {Array} Formatted size 89 | */ 90 | formatSize(size) { 91 | if (Array.isArray(size)) { 92 | return size; 93 | } 94 | if (typeof size === 'string') { 95 | return size.split('x').map(value => parseInt(value, 10)); 96 | } 97 | return []; 98 | }, 99 | /** 100 | * Formats a given list of sizes to make it compatible with GPT API 101 | * If sizesList is an Array, it is returned as is 102 | * If sizesList is a string, it is formatted so that 103 | * 123x456,654x321 becomes [[123, 456], [654, 321]] 104 | * 105 | * @param {Array,string} sizesList The sizes 106 | * @return {Array} Formatted sizes list 107 | */ 108 | formatSizeList(sizesList) { 109 | if (Array.isArray(sizesList)) { 110 | return sizesList; 111 | } 112 | if (typeof sizesList === 'string') { 113 | return sizesList 114 | .split(',') 115 | .map(size => this.formatSize(size)); 116 | } 117 | return []; 118 | }, 119 | /** 120 | * Refresh ad slot 121 | */ 122 | refreshSlot() { 123 | googletag.pubads().refresh([this.adSlot]); 124 | }, 125 | handleSlotRenderEnded (event) { 126 | if (event.slot.getSlotId().getDomId() !== this.divId) { 127 | return; 128 | } 129 | this.isEmpty = !!event.isEmpty; 130 | }, 131 | /** 132 | * Window resize event listener 133 | * Attached only when responsive mode is enabled, it checks wether a different size 134 | * mapping can be activated after resize and forces the slot to be refreshed if it's 135 | * the case 136 | */ 137 | handleWindowResize() { 138 | const { windowResizeDebounce } = this; 139 | clearTimeout(this.windowResizeListenerDebounce); 140 | this.windowResizeListenerDebounce = setTimeout(() => { 141 | const currentSizeMappingIndex = this.getCurrentSizeMappingIndex(); 142 | if (currentSizeMappingIndex !== this.currentSizeMappingIndex) { 143 | if (!this.ghostMode) { 144 | this.refreshSlot(); 145 | } 146 | this.currentSizeMappingIndex = currentSizeMappingIndex; 147 | } 148 | }, windowResizeDebounce); 149 | }, 150 | /** 151 | * Gets the current size mapping index 152 | * 153 | * @return {Number} The current size mapping index 154 | */ 155 | getCurrentSizeMappingIndex() { 156 | const mapping = this.mapping || []; 157 | let index = null; 158 | mapping.some((size, i) => { 159 | const [browserSize] = size; 160 | const [width, height] = browserSize; 161 | const mediaQuery = `(min-width: ${width}px) and (min-height: ${height}px)`; 162 | if (window.matchMedia(mediaQuery).matches) { 163 | index = i; 164 | return true; 165 | } 166 | return false; 167 | }); 168 | return index; 169 | }, 170 | }, 171 | mounted() { 172 | if (!window.googletag) { 173 | return; 174 | } 175 | const { 176 | ghostMode, 177 | adUnitPath, 178 | divId, 179 | sizeMapping, 180 | isResponsive, 181 | collapseEmptyDiv, 182 | } = this; 183 | 184 | 185 | // Init Ad slot 186 | googletag.cmd.push(() => { 187 | const pubadsService = googletag.pubads() 188 | pubadsService.addEventListener('slotRenderEnded', this.handleSlotRenderEnded); 189 | 190 | const adSlot = googletag 191 | .defineSlot(adUnitPath, this.formattedSize, divId) 192 | .addService(pubadsService); 193 | 194 | // Collapse empty div slot-level override 195 | if (collapseEmptyDiv !== null) { 196 | adSlot.setCollapseEmptyDiv(collapseEmptyDiv); 197 | } 198 | 199 | // Build size mapping if any 200 | if (sizeMapping.length > 0) { 201 | const mapping = googletag.sizeMapping(); 202 | sizeMapping.forEach((size) => { 203 | const browserSize = this.formatSize(size[0]); 204 | const adSizes = this.formatSizeList(size[1]); 205 | mapping.addSize(browserSize, adSizes); 206 | this.mapping.push([browserSize, adSizes]); 207 | }); 208 | adSlot.defineSizeMapping(mapping.build()); 209 | } 210 | 211 | // Init responsive behavior 212 | if (this.sizeMapping.length > 0 && isResponsive) { 213 | const currentSizeMappingIndex = this.getCurrentSizeMappingIndex(); 214 | this.currentSizeMappingIndex = currentSizeMappingIndex; 215 | window.addEventListener('resize', this.handleWindowResize); 216 | } 217 | 218 | this.adSlot = adSlot; 219 | this.$gptAds.slots.push(adSlot); 220 | 221 | if (!this.ghostMode) { 222 | googletag.display(divId); 223 | if (this.$gptAds.individualRefresh) { 224 | this.refreshSlot(); 225 | } 226 | } 227 | }); 228 | }, 229 | beforeDestroy() { 230 | if (!googletag) { 231 | return; 232 | } 233 | // Destroy ad slot 234 | googletag.cmd.push(() => { 235 | const destroyed = googletag.destroySlots([this.adSlot]); 236 | }); 237 | // Remove window resize listener 238 | window.removeEventListener('resize', this.handleWindowResize); 239 | }, 240 | render(h) { 241 | const { divId, style, isEmpty } = this; 242 | let classAttr = isEmpty ? '<%= options.emptyClass %>' : ''; 243 | 244 | return h('div', { 245 | style, 246 | attrs: { 247 | id: divId, 248 | class: classAttr, 249 | }, 250 | domProps: { innerHTML: '' }, 251 | }); 252 | }, 253 | }; 254 | --------------------------------------------------------------------------------