Added mobile friendly ads & ads (#161)

* Fix spacing issues on mobile

* Added back linting on modules directory.
Please don't look at the dirty fixes :x

* Add support for responsive ads.

* Add lazy loading of images.
This commit is contained in:
Redblueflame
2021-04-15 15:48:33 +02:00
committed by GitHub
parent 28092d6862
commit 0bda636113
15 changed files with 289 additions and 229 deletions

View File

@@ -1,3 +1,2 @@
node_modules/ node_modules/
jspm_packages/ jspm_packages/
modules/*

View File

@@ -1,25 +1,90 @@
<template> <template>
<div class="ad-wrapper"> <div class="ad-wrapper">
<div class="ad"> <div v-if="displayed" class="ad">
<GptAd :ad-unit="adUnit" :size="size" /> <GptAd
:key="format.adUnit"
ref="ad_slot"
:ad-unit="format.adUnit"
:size="format.size"
:is-responsive="true"
/>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
const sizes = {
banner: {
adUnit: 'banner',
size: '728x90,468x60',
},
square: {
adUnit: 'square',
size: '250x250,200x200',
},
}
/* eslint-disable no-undef */ /* eslint-disable no-undef */
export default { export default {
name: 'Advertisement', name: 'Advertisement',
props: { props: {
size: { type: {
type: String, type: String,
required: true, required: true,
}, },
adUnit: { smallScreen: {
type: String, type: String,
required: true, required: true,
}, },
}, },
data() {
return {
format: null,
displayed: false,
onSmallScreen: false,
windowResizeListenerDebounce: null,
}
},
mounted() {
// Register hook on resize
window.addEventListener('resize', this.handleWindowResize)
// Find ad
if (!(this.type in sizes)) {
console.error('Ad type not recognized.')
return
}
// Set the informations
this.format = sizes[this.type]
this.displayed = true
if (process.browser) {
this.handleWindowResize()
}
},
methods: {
handleWindowResize() {
clearTimeout(this.windowResizeListenerDebounce)
this.windowResizeListenerDebounce = setTimeout(() => {
if (window.innerWidth > 1024) {
if (this.onSmallScreen) {
// Return everything to normal size
this.onSmallScreen = false
this.format = sizes[this.type]
this.displayed = true
}
return
}
this.onSmallScreen = true
if (this.smallScreen === 'destroy') {
this.displayed = false
} else if (this.smallScreen in sizes) {
console.log('Changing ad size to ', this.smallScreen)
this.format = sizes[this.smallScreen]
}
}, 300)
},
},
} }
</script> </script>

View File

@@ -65,8 +65,8 @@
</div> </div>
<Advertisement <Advertisement
v-if="mod.status === 'approved' || mod.status === 'unlisted'" v-if="mod.status === 'approved' || mod.status === 'unlisted'"
ad-unit="banner" type="banner"
size="728x90,468x60" small-screen="square"
/> />
<div class="mod-navigation"> <div class="mod-navigation">
<div class="tabs"> <div class="tabs">
@@ -130,11 +130,6 @@
</div> </div>
<div class="mod-content"> <div class="mod-content">
<slot /> <slot />
<Advertisement
v-if="mod.status === 'approved' || mod.status === 'unlisted'"
ad-unit="banner"
size="728x90,468x60"
/>
</div> </div>
</div> </div>
<section class="mod-info"> <section class="mod-info">
@@ -331,8 +326,8 @@
</div> </div>
<Advertisement <Advertisement
v-if="mod.status === 'approved' || mod.status === 'unlisted'" v-if="mod.status === 'approved' || mod.status === 'unlisted'"
ad-unit="square" type="square"
size="250x250,200x200" small-screen="destroy"
/> />
<m-footer class="footer" /> <m-footer class="footer" />
</section> </section>

View File

@@ -6,6 +6,7 @@
<img <img
:src="iconUrl || 'https://cdn.modrinth.com/placeholder.svg?inline'" :src="iconUrl || 'https://cdn.modrinth.com/placeholder.svg?inline'"
:alt="name" :alt="name"
loading="lazy"
/> />
</nuxt-link> </nuxt-link>
</div> </div>

View File

@@ -1,6 +1,6 @@
export const DEFAULT_OPTIONS = { export const DEFAULT_OPTIONS = {
enabled: false, enabled: false,
script_url: 'https://example.com', script_url: 'https://example.com',
tracking_code: 'xxx' tracking_code: 'xxx',
} }
export const UNAMI_LIB_TAG_ID = 'unami-import' export const UNAMI_LIB_TAG_ID = 'unami-import'

View File

@@ -1,22 +1,24 @@
import { import { DEFAULT_OPTIONS, UNAMI_LIB_TAG_ID } from './constants'
DEFAULT_OPTIONS,
UNAMI_LIB_TAG_ID
} from './constants';
const { resolve } = require('path'); const { resolve } = require('path')
// eslint-disable-next-line require-await
module.exports = async function module(moduleOptions) { module.exports = async function module(moduleOptions) {
const options = Object.assign(DEFAULT_OPTIONS, this.options.analytics, moduleOptions); const options = Object.assign(
DEFAULT_OPTIONS,
this.options.analytics,
moduleOptions
)
const templatesOptions = { const templatesOptions = {
...options, ...options,
UNAMI_LIB_TAG_ID UNAMI_LIB_TAG_ID,
}; }
this.addPlugin({ this.addPlugin({
src: resolve(__dirname, 'templates/plugin.js'), src: resolve(__dirname, 'templates/plugin.js'),
fileName: 'analytics/plugin.js', fileName: 'analytics/plugin.js',
options: templatesOptions, options: templatesOptions,
}); })
}; }
module.exports.meta = require('../package.json'); module.exports.meta = require('../package.json')

View File

@@ -1,64 +1,35 @@
import Vue from 'vue'; // eslint-disable-next-line require-await
function isAnalyticsOn(ctx) {
let cookies = null
if (ctx.req != null) {
//Server side rendering
cookies = ctx.req.headers.cookie;
} else {
// Rely on the client
cookies = document.cookie;
}
if (cookies == null) return false
let processed = {}
cookies.split(';').forEach((e) => {
let val = e.trim().split('=');
processed[val[0]] = decodeURI(val[1]);
})
let scopes = decodeURIComponent(processed['modrinth-scopes']).split(",");
return (scopes !== null && scopes.includes('analytics'));
}
export default async function (ctx, inject) { export default async function (ctx, inject) {
const config = (ctx.$config && ctx.$config.analytics) || {}
const { app } = ctx; const url = config.script_url ?? '<%= options.script_url %>'
const config = ctx.$config && ctx.$config.analytics || {}; const tag = config.tracking_code ?? '<%= options.tracking_code %>'
// eslint-disable-next-line
const url = config.script_url ?? '<%= options.script_url %>'; const enabled = config.enabled ?? ('<%= options.enabled || false %>' === 'true');
const tag = config.tracking_code ?? '<%= options.tracking_code %>';
const enabled = config.enabled ?? <%= options.enabled || false %>;
// Check if the parameters are not changed by runtime config: // Check if the parameters are not changed by runtime config:
const UNAMI_LIB_TAG_ID = '<%= options.UNAMI_LIB_TAG_ID %>'
const UNAMI_LIB_TAG_ID = '<%= options.UNAMI_LIB_TAG_ID %>';
if (!enabled) { if (!enabled) {
return; return
} }
const injectScript = (script) => { const injectScript = (script) => {
const scriptIndex = ctx.app.head.script.findIndex(s => s.hid === script.hid); const scriptIndex = ctx.app.head.script.findIndex(
(s) => s.hid === script.hid
)
if (scriptIndex !== -1) { if (scriptIndex !== -1) {
ctx.app.head.script[scriptIndex] = script; ctx.app.head.script[scriptIndex] = script
} else { } else {
ctx.app.head.script.push(script); ctx.app.head.script.push(script)
} }
}; }
// if (isAnalyticsOn(ctx)) { const analyticsScript = {
// Inject unami hid: UNAMI_LIB_TAG_ID,
const analyticsScript = { src: url,
hid: UNAMI_LIB_TAG_ID, 'data-website-id': tag,
src: url, async: true,
'data-website-id': 'c37613de-245d-4767-90e7-ba7980a4f1a2', defer: true,
async: true, }
defer: true, injectScript(analyticsScript)
};
injectScript(analyticsScript);
// } else {
// console.log("Analytics scope was denied.")
// }
} }

View File

@@ -7,10 +7,10 @@ export const DEFAULT_OPTIONS = {
responsive: false, responsive: false,
collapseEmptyDivs: false, collapseEmptyDivs: false,
emptyClass: 'is-empty', emptyClass: 'is-empty',
geoEdgeId: '' geoEdgeId: '',
}; }
export const GPT_LIB_SCRIPT_ID = 'google-publisher-tag-lib-script'; export const GPT_LIB_SCRIPT_ID = 'google-publisher-tag-lib-script'
export const GPT_INIT_SCRIPT_ID = 'google-publisher-tag-init-script'; export const GPT_INIT_SCRIPT_ID = 'google-publisher-tag-init-script'
export const GEOEDGE_CONF_SCRIPT_ID = 'geoedge-config-script'; export const GEOEDGE_CONF_SCRIPT_ID = 'geoedge-config-script'
export const GEOEDGE_LIB_SCRIPT_ID = 'geoedge-lib-script'; export const GEOEDGE_LIB_SCRIPT_ID = 'geoedge-lib-script'

View File

@@ -4,12 +4,17 @@ import {
GPT_INIT_SCRIPT_ID, GPT_INIT_SCRIPT_ID,
GEOEDGE_CONF_SCRIPT_ID, GEOEDGE_CONF_SCRIPT_ID,
GEOEDGE_LIB_SCRIPT_ID, GEOEDGE_LIB_SCRIPT_ID,
} from './constants'; } from './constants'
const { resolve } = require('path'); const { resolve } = require('path')
// eslint-disable-next-line require-await
module.exports = async function module(moduleOptions) { module.exports = async function module(moduleOptions) {
const options = Object.assign(DEFAULT_OPTIONS, this.options.ads, moduleOptions); const options = Object.assign(
DEFAULT_OPTIONS,
this.options.ads,
moduleOptions
)
const templatesOptions = { const templatesOptions = {
...options, ...options,
@@ -17,18 +22,18 @@ module.exports = async function module(moduleOptions) {
GPT_INIT_SCRIPT_ID, GPT_INIT_SCRIPT_ID,
GEOEDGE_CONF_SCRIPT_ID, GEOEDGE_CONF_SCRIPT_ID,
GEOEDGE_LIB_SCRIPT_ID, GEOEDGE_LIB_SCRIPT_ID,
}; }
this.addPlugin({ this.addPlugin({
src: resolve(__dirname, 'templates/plugin.js'), src: resolve(__dirname, 'templates/plugin.js'),
fileName: 'gpt-ads-module/plugin.js', fileName: 'gpt-ads-module/plugin.js',
options: templatesOptions, options: templatesOptions,
}); })
this.addTemplate({ this.addTemplate({
src: resolve(__dirname, 'templates/component.js'), src: resolve(__dirname, 'templates/component.js'),
fileName: 'gpt-ads-module/component.js', fileName: 'gpt-ads-module/component.js',
options: templatesOptions, options: templatesOptions,
}); })
}; }
module.exports.meta = require('../package.json'); module.exports.meta = require('../package.json')

View File

@@ -1,3 +1,4 @@
/* eslint-disable no-undef */
export default { export default {
name: '<%= options.componentName %>', name: '<%= options.componentName %>',
data: () => ({ data: () => ({
@@ -29,7 +30,7 @@ export default {
isResponsive: { isResponsive: {
type: Boolean, type: Boolean,
required: false, required: false,
default: <%= options.responsive %>, default: '<%= options.responsive %>' === 'true',
}, },
windowResizeDebounce: { windowResizeDebounce: {
type: Number, type: Number,
@@ -44,40 +45,42 @@ export default {
}, },
computed: { computed: {
ghostMode() { ghostMode() {
return this.$config.ads.ghostMode ?? <%= options.ghostMode %>; return this.$config.ads.ghostMode ?? '<%= options.ghostMode %>' === true
}, },
networkCode() { networkCode() {
const { $gptAds } = this; const { $gptAds } = this
return $gptAds ? $gptAds.networkCode : null; return $gptAds ? $gptAds.networkCode : null
}, },
adUnitPath() { adUnitPath() {
const { networkCode, adUnit } = this; const { networkCode, adUnit } = this
return `/${networkCode}/${adUnit}`; return `/${networkCode}/${adUnit}`
}, },
divId() { divId() {
const { id } = this; const { id } = this
return `div-gpt-ad-${id}-0`; return `div-gpt-ad-${id}-0`
}, },
formattedSize() { formattedSize() {
return this.formatSizeList(this.size); return this.formatSizeList(this.size)
}, },
style() { style() {
if (this.ghostMode) { if (this.ghostMode) {
const { formattedSize, currentSizeMappingIndex, mapping } = this; const { formattedSize, currentSizeMappingIndex, mapping } = this
let baseSize = formattedSize; let baseSize = formattedSize
if (currentSizeMappingIndex !== null) { if (currentSizeMappingIndex !== null) {
baseSize = mapping[currentSizeMappingIndex][1]; baseSize = mapping[currentSizeMappingIndex][1]
} }
const size = Array.isArray(baseSize[0]) ? baseSize[0] : [baseSize[0], baseSize[1]]; const size = Array.isArray(baseSize[0])
const [width, height] = size; ? baseSize[0]
: [baseSize[0], baseSize[1]]
const [width, height] = size
return { return {
margin: '0 auto', margin: '0 auto',
width: `${width}px`, width: `${width}px`,
height: `${height}px`, height: `${height}px`,
border: '1px solid black', border: '1px solid black',
}; }
} }
return null; return null
}, },
}, },
methods: { methods: {
@@ -91,12 +94,12 @@ export default {
*/ */
formatSize(size) { formatSize(size) {
if (Array.isArray(size)) { if (Array.isArray(size)) {
return size; return size
} }
if (typeof size === 'string') { if (typeof size === 'string') {
return size.split('x').map(value => parseInt(value, 10)); return size.split('x').map((value) => parseInt(value, 10))
} }
return []; return []
}, },
/** /**
* Formats a given list of sizes to make it compatible with GPT API * Formats a given list of sizes to make it compatible with GPT API
@@ -109,26 +112,25 @@ export default {
*/ */
formatSizeList(sizesList) { formatSizeList(sizesList) {
if (Array.isArray(sizesList)) { if (Array.isArray(sizesList)) {
return sizesList; return sizesList
} }
if (typeof sizesList === 'string') { if (typeof sizesList === 'string') {
return sizesList return sizesList.split(',').map((size) => this.formatSize(size))
.split(',')
.map(size => this.formatSize(size));
} }
return []; return []
}, },
/** /**
* Refresh ad slot * Refresh ad slot
*/ */
refreshSlot() { refreshSlot() {
googletag.pubads().refresh([this.adSlot]); console.log('Refreshing slot.')
googletag.pubads().refresh([this.adSlot])
}, },
handleSlotRenderEnded (event) { handleSlotRenderEnded(event) {
if (event.slot.getSlotId().getDomId() !== this.divId) { if (event.slot.getSlotId().getDomId() !== this.divId) {
return; return
} }
this.isEmpty = !!event.isEmpty; this.isEmpty = !!event.isEmpty
}, },
/** /**
* Window resize event listener * Window resize event listener
@@ -137,17 +139,17 @@ export default {
* the case * the case
*/ */
handleWindowResize() { handleWindowResize() {
const { windowResizeDebounce } = this; const { windowResizeDebounce } = this
clearTimeout(this.windowResizeListenerDebounce); clearTimeout(this.windowResizeListenerDebounce)
this.windowResizeListenerDebounce = setTimeout(() => { this.windowResizeListenerDebounce = setTimeout(() => {
const currentSizeMappingIndex = this.getCurrentSizeMappingIndex(); const currentSizeMappingIndex = this.getCurrentSizeMappingIndex()
if (currentSizeMappingIndex !== this.currentSizeMappingIndex) { if (currentSizeMappingIndex !== this.currentSizeMappingIndex) {
if (!this.ghostMode) { if (!this.ghostMode) {
this.refreshSlot(); this.refreshSlot()
} }
this.currentSizeMappingIndex = currentSizeMappingIndex; this.currentSizeMappingIndex = currentSizeMappingIndex
} }
}, windowResizeDebounce); }, windowResizeDebounce)
}, },
/** /**
* Gets the current size mapping index * Gets the current size mapping index
@@ -155,94 +157,96 @@ export default {
* @return {Number} The current size mapping index * @return {Number} The current size mapping index
*/ */
getCurrentSizeMappingIndex() { getCurrentSizeMappingIndex() {
const mapping = this.mapping || []; const mapping = this.mapping || []
let index = null; let index = null
mapping.some((size, i) => { mapping.some((size, i) => {
const [browserSize] = size; const [browserSize] = size
const [width, height] = browserSize; const [width, height] = browserSize
const mediaQuery = `(min-width: ${width}px) and (min-height: ${height}px)`; const mediaQuery = `(min-width: ${width}px) and (min-height: ${height}px)`
if (window.matchMedia(mediaQuery).matches) { if (window.matchMedia(mediaQuery).matches) {
index = i; index = i
return true; return true
} }
return false; return false
}); })
return index; return index
}, },
}, },
mounted() { mounted() {
if (!window.googletag) { if (!window.googletag) {
return; return
} }
const { const {
ghostMode,
adUnitPath, adUnitPath,
divId, divId,
sizeMapping, sizeMapping,
isResponsive, isResponsive,
collapseEmptyDiv, collapseEmptyDiv,
} = this; } = this
// Init Ad slot // Init Ad slot
googletag.cmd.push(() => { googletag.cmd.push(() => {
const pubadsService = googletag.pubads() const pubadsService = googletag.pubads()
pubadsService.addEventListener('slotRenderEnded', this.handleSlotRenderEnded); pubadsService.addEventListener(
pubadsService.setTargeting('path', this.$route.path); 'slotRenderEnded',
this.handleSlotRenderEnded
)
pubadsService.setTargeting('path', this.$route.path)
const adSlot = googletag const adSlot = googletag
.defineSlot(adUnitPath, this.formattedSize, divId) .defineSlot(adUnitPath, this.formattedSize, divId)
.addService(pubadsService); .addService(pubadsService)
// Collapse empty div slot-level override // Collapse empty div slot-level override
if (collapseEmptyDiv !== null) { if (collapseEmptyDiv !== null) {
adSlot.setCollapseEmptyDiv(collapseEmptyDiv); adSlot.setCollapseEmptyDiv(collapseEmptyDiv)
} }
// Build size mapping if any // Build size mapping if any
if (sizeMapping.length > 0) { if (sizeMapping.length > 0) {
const mapping = googletag.sizeMapping(); const mapping = googletag.sizeMapping()
sizeMapping.forEach((size) => { sizeMapping.forEach((size) => {
const browserSize = this.formatSize(size[0]); const browserSize = this.formatSize(size[0])
const adSizes = this.formatSizeList(size[1]); const adSizes = this.formatSizeList(size[1])
mapping.addSize(browserSize, adSizes); mapping.addSize(browserSize, adSizes)
this.mapping.push([browserSize, adSizes]); this.mapping.push([browserSize, adSizes])
}); })
adSlot.defineSizeMapping(mapping.build()); adSlot.defineSizeMapping(mapping.build())
} }
// Init responsive behavior // Init responsive behavior
if (this.sizeMapping.length > 0 && isResponsive) { if (this.sizeMapping.length > 0 && isResponsive) {
const currentSizeMappingIndex = this.getCurrentSizeMappingIndex(); const currentSizeMappingIndex = this.getCurrentSizeMappingIndex()
this.currentSizeMappingIndex = currentSizeMappingIndex; this.currentSizeMappingIndex = currentSizeMappingIndex
window.addEventListener('resize', this.handleWindowResize); window.addEventListener('resize', this.handleWindowResize)
} }
this.adSlot = adSlot; this.adSlot = adSlot
this.$gptAds.slots.push(adSlot); this.$gptAds.slots.push(adSlot)
if (!this.ghostMode) { if (!this.ghostMode) {
googletag.display(divId); googletag.display(divId)
if (this.$gptAds.individualRefresh) { if (this.$gptAds.individualRefresh) {
this.refreshSlot(); this.refreshSlot()
} }
} }
}); })
}, },
beforeDestroy() { beforeDestroy() {
console.log('Destroying ad.')
if (!googletag) { if (!googletag) {
return; return
} }
// Destroy ad slot // Destroy ad slot
googletag.cmd.push(() => { googletag.cmd.push(() => {
const destroyed = googletag.destroySlots([this.adSlot]); googletag.destroySlots([this.adSlot])
}); })
// Remove window resize listener // Remove window resize listener
window.removeEventListener('resize', this.handleWindowResize); window.removeEventListener('resize', this.handleWindowResize)
}, },
render(h) { render(h) {
const { divId, style, isEmpty } = this; const { divId, style, isEmpty } = this
let classAttr = isEmpty ? '<%= options.emptyClass %>' : ''; const classAttr = isEmpty ? '<%= options.emptyClass %>' : ''
return h('div', { return h('div', {
style, style,
@@ -251,6 +255,6 @@ export default {
class: classAttr, class: classAttr,
}, },
domProps: { innerHTML: '' }, domProps: { innerHTML: '' },
}); })
}, },
}; }

View File

@@ -1,71 +1,80 @@
import Vue from 'vue'; import Vue from 'vue'
function isPersonalizedAdsOn(ctx) { function isPersonalizedAdsOn(ctx) {
let cookies = [] let cookies = []
if (ctx.req != null) { if (ctx.req != null) {
//Server side rendering // Server side rendering
cookies = ctx.req.headers.cookie; cookies = ctx.req.headers.cookie
} else { } else {
// Rely on the client // Rely on the client
cookies = document.cookie; cookies = document.cookie
} }
if (cookies == null) return false if (cookies == null) return false
let processed = {} const processed = {}
cookies.split(';').forEach((e) => { cookies.split(';').forEach((e) => {
let val = e.trim().split('=') const val = e.trim().split('=')
processed[val[0]] = decodeURI(val[1]) processed[val[0]] = decodeURI(val[1])
}) })
let scopes = decodeURIComponent(processed['modrinth-scopes']).split(",") const scopes = decodeURIComponent(processed['modrinth-scopes']).split(',')
return (scopes !== null && scopes.includes('ads')) return scopes !== null && scopes.includes('ads')
} }
// eslint-disable-next-line require-await
export default async function (ctx, inject) { export default async function (ctx, inject) {
const config = (ctx.$config && ctx.$config.ads) || {}
const { app } = ctx;
const config = ctx.$config && ctx.$config.ads || {};
// Module options // Module options
const debug = config.debug ?? <%= options.debug || false %>; const debug = config.debug ?? '<%= options.debug || false %>' === 'true'
const individualRefresh = config.individualRefresh ?? <%= options.individualRefresh || false %>; const individualRefresh =
const collapseEmptyDivs = config.collapseEmptyDivs ?? <%= options.collapseEmptyDivs || false %>; config.individualRefresh ??
const GeoEdgeId = config.GeoEdgeId ?? '<%= options.geoEdgeId %>'; '<%= options.individualRefresh || false %>' === 'true'
const networkCode = config.networkCode ?? '<%= options.networkCode %>'; const collapseEmptyDivs =
const GPT_LIB_SCRIPT_ID = '<%= options.GPT_LIB_SCRIPT_ID %>'; config.collapseEmptyDivs ??
const GPT_INIT_SCRIPT_ID = '<%= options.GPT_INIT_SCRIPT_ID %>'; '<%= options.collapseEmptyDivs || false %>' === 'true'
const GEOEDGE_CONF_SCRIPT_ID = '<%= options.GEOEDGE_CONF_SCRIPT_ID %>'; const GeoEdgeId = config.GeoEdgeId ?? '<%= options.geoEdgeId %>'
const GEOEDGE_LIB_SCRIPT_ID = '<%= options.GEOEDGE_LIB_SCRIPT_ID %>'; const networkCode = config.networkCode ?? '<%= options.networkCode %>'
const GPT_LIB_SCRIPT_ID = '<%= options.GPT_LIB_SCRIPT_ID %>'
const GPT_INIT_SCRIPT_ID = '<%= options.GPT_INIT_SCRIPT_ID %>'
const GEOEDGE_CONF_SCRIPT_ID = '<%= options.GEOEDGE_CONF_SCRIPT_ID %>'
const GEOEDGE_LIB_SCRIPT_ID = '<%= options.GEOEDGE_LIB_SCRIPT_ID %>'
// Instance options // Instance options
const gptAdsOptions = { const gptAdsOptions = {
networkCode, networkCode,
individualRefresh, individualRefresh,
slots: [], slots: [],
}; }
const injectScript = (script) => { const injectScript = (script) => {
const scriptIndex = ctx.app.head.script.findIndex(s => s.hid === script.hid); const scriptIndex = ctx.app.head.script.findIndex(
(s) => s.hid === script.hid
)
if (scriptIndex !== -1) { if (scriptIndex !== -1) {
ctx.app.head.script[scriptIndex] = script; ctx.app.head.script[scriptIndex] = script
} else { } else {
ctx.app.head.script.push(script); ctx.app.head.script.push(script)
} }
}; }
let no_consent = !isPersonalizedAdsOn(ctx) const noConsent = !isPersonalizedAdsOn(ctx)
// GeoEdge support // GeoEdge support
if (GeoEdgeId !== '') { if (GeoEdgeId !== '') {
// Unfortunately these lines are needed to prevent vue-meta from esacping quotes in the init script // Unfortunately these lines are needed to prevent vue-meta from esacping quotes in the init script
ctx.app.head.__dangerouslyDisableSanitizersByTagID = ctx.app.head.__dangerouslyDisableSanitizersByTagID || {} ctx.app.head.__dangerouslyDisableSanitizersByTagID =
ctx.app.head.__dangerouslyDisableSanitizersByTagID[GEOEDGE_CONF_SCRIPT_ID] = ['innerHTML'] ctx.app.head.__dangerouslyDisableSanitizersByTagID || {}
ctx.app.head.__dangerouslyDisableSanitizersByTagID[
GEOEDGE_CONF_SCRIPT_ID
] = ['innerHTML']
const geoEdgeConfig = { const geoEdgeConfig = {
hid: GEOEDGE_CONF_SCRIPT_ID, hid: GEOEDGE_CONF_SCRIPT_ID,
innerHTML: "window.grumi = { key: '" + encodeURIComponent(GeoEdgeId) +"'};" innerHTML:
}; "window.grumi = { key: '" + encodeURIComponent(GeoEdgeId) + "'};",
injectScript(geoEdgeConfig); }
injectScript(geoEdgeConfig)
const geoEdgeImport = { const geoEdgeImport = {
hid: GEOEDGE_LIB_SCRIPT_ID, hid: GEOEDGE_LIB_SCRIPT_ID,
src: `https://rumcdn.geoedge.be/${GeoEdgeId}/grumi-ip.js`, src: `https://rumcdn.geoedge.be/${GeoEdgeId}/grumi-ip.js`,
async: true, async: true,
}; }
injectScript(geoEdgeImport) injectScript(geoEdgeImport)
} }
@@ -74,20 +83,28 @@ export default async function (ctx, inject) {
hid: GPT_LIB_SCRIPT_ID, hid: GPT_LIB_SCRIPT_ID,
src: 'https://www.googletagservices.com/tag/js/gpt.js', src: 'https://www.googletagservices.com/tag/js/gpt.js',
async: true, async: true,
}; }
injectScript(gptLibScript); injectScript(gptLibScript)
// Inject GPT init script // Inject GPT init script
let gptInitScriptHtml = 'var googletag = googletag || {};googletag.cmd = googletag.cmd || [];'; let gptInitScriptHtml =
'var googletag = googletag || {};googletag.cmd = googletag.cmd || [];'
if (debug) { if (debug) {
gptInitScriptHtml += 'googletag.cmd.push(function(){googletag.openConsole();});'; gptInitScriptHtml +=
'googletag.cmd.push(function(){googletag.openConsole();});'
} }
// Disable initial load // Disable initial load
const gptDisableInitialLoad = individualRefresh ? 'googletag.pubads().disableInitialLoad();' : ''; const gptDisableInitialLoad = individualRefresh
? 'googletag.pubads().disableInitialLoad();'
: ''
// Collapse empty div // Collapse empty div
const gptCollapseEmptyDivs = collapseEmptyDivs ? 'googletag.pubads().collapseEmptyDivs();' : ''; const gptCollapseEmptyDivs = collapseEmptyDivs
? 'googletag.pubads().collapseEmptyDivs();'
: ''
// Desactivate personalization // Desactivate personalization
const gptDisablePersonalization = no_consent ? 'googletag.pubads().setRequestNonPersonalizedAds(1);' : ''; const gptDisablePersonalization = noConsent
? 'googletag.pubads().setRequestNonPersonalizedAds(1);'
: ''
gptInitScriptHtml += ` gptInitScriptHtml += `
googletag.cmd.push(function(){ googletag.cmd.push(function(){
googletag.pubads().enableSingleRequest(); googletag.pubads().enableSingleRequest();
@@ -96,17 +113,15 @@ export default async function (ctx, inject) {
${gptDisablePersonalization} ${gptDisablePersonalization}
googletag.enableServices(); googletag.enableServices();
}); });
`; `
const gptInitScript = { const gptInitScript = {
hid: GPT_INIT_SCRIPT_ID, hid: GPT_INIT_SCRIPT_ID,
innerHTML: gptInitScriptHtml, innerHTML: gptInitScriptHtml,
}; }
injectScript(gptInitScript); injectScript(gptInitScript)
const component = require('./component.js')
Vue.component('<%= options.componentName %>', component.default || component)
const component = require('./component.js'); inject('gptAds', gptAdsOptions)
Vue.component('<%= options.componentName %>', component.default || component);
inject('gptAds', gptAdsOptions);
} }

View File

@@ -9,7 +9,8 @@
"export": "nuxt export", "export": "nuxt export",
"serve": "nuxt serve", "serve": "nuxt serve",
"lint:js": "eslint --ext .js,.vue --ignore-path .eslintignore .", "lint:js": "eslint --ext .js,.vue --ignore-path .eslintignore .",
"lint": "npm run lint:js" "lint": "npm run lint:js",
"fix": "eslint --fix --ext .js,.vue --ignore-path .eslintignore ."
}, },
"dependencies": { "dependencies": {
"@nuxtjs/axios": "^5.12.5", "@nuxtjs/axios": "^5.12.5",

View File

@@ -120,12 +120,14 @@ export default {
margin-top: 1rem; margin-top: 1rem;
} }
.actions { .actions {
margin-top: 1.5rem; margin-top: 1rem;
margin-right: -0.5rem; margin-right: -0.5rem;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
justify-content: flex-end; justify-content: flex-end;
flex-wrap: wrap;
.btn { .btn {
margin-top: 0.5rem;
margin-right: 0.5rem; margin-right: 0.5rem;
} }
} }

View File

@@ -64,7 +64,7 @@
></pagination> ></pagination>
</section> </section>
<div class="results column-grow-4"> <div class="results column-grow-4">
<Advertisement ad-unit="banner" size="728x90,468x60" /> <Advertisement type="banner" small-screen="square" />
<div v-if="results === null" class="no-results"> <div v-if="results === null" class="no-results">
<p>Loading...</p> <p>Loading...</p>
</div> </div>
@@ -283,7 +283,7 @@
@input="toggleLicense" @input="toggleLicense"
/> />
</div> </div>
<Advertisement ad-unit="square" size="250x250,200x200" /> <Advertisement type="square" small-screen="destroy" />
<m-footer class="footer" hide-small /> <m-footer class="footer" hide-small />
</section> </section>
</div> </div>

View File

@@ -55,11 +55,11 @@
</div> </div>
</div> </div>
</div> </div>
<Advertisement ad-unit="square" size="250x250,200x200" /> <Advertisement type="square" small-screen="square" />
<m-footer class="footer" hide-small /> <m-footer class="footer" hide-small />
</div> </div>
<div class="content"> <div class="content">
<Advertisement ad-unit="banner" size="728x90,468x60" /> <Advertisement type="banner" small-screen="destroy" />
<div class="mods"> <div class="mods">
<SearchResult <SearchResult
v-for="result in mods" v-for="result in mods"