Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Images): Add asset image support for wysiwyg node type #40

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions gatsby-node.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,8 @@ exports.sourceNodes = async (
images,
assets,
markdowns,
layouts
layouts,
configOptions.baseUrl
)

collection.items.forEach(item => {
Expand All @@ -112,7 +113,8 @@ exports.sourceNodes = async (
images,
assets,
markdowns,
layouts
layouts,
configOptions.baseUrl
)

singleton.items.forEach(item => {
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@fika/gatsby-source-cockpit",
"version": "1.1.1",
"description": "This is a Gatsby version 2.x.x source plugin that feeds the GraphQL tree with Cockpit Headless CMS collections and singletons data. Actually, it supports querying raw texts (and any trivial field types), Markdown, images, galleries, assets, sets, repeaters, layout(-grid)s (currently only without nested images/assets), objects, linked collections and internationalization.",
"version": "1.1.2",
"description": "This is a Gatsby version 2.x.x source plugin that feeds the GraphQL tree with Cockpit Headless CMS collections and singletons data. Actually, it supports querying raw texts (and any trivial field types), Markdown, Wysiwyg, images, galleries, assets, sets, repeaters, layout(-grid)s (currently only without nested images/assets), objects, linked collections and internationalization.",
"main": "gatsby-node.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
Expand Down Expand Up @@ -46,7 +46,8 @@
"react-styling": "^1.6.4",
"sanitize-html": "^1.20.0",
"slugify": "^1.3.4",
"string-hash": "^1.1.3"
"string-hash": "^1.1.3",
"node-html-parser": "1.1.16"
},
"devDependencies": {
"husky": "^1.3.1",
Expand Down
6 changes: 5 additions & 1 deletion readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This is a Gatsby version 2.\*.\* source plugin that feeds the GraphQL tree with Cockpit Headless CMS collections and singletons data.

Actually, it supports querying raw texts (and any trivial field types), Markdown, images, galleries, assets, sets, repeaters, layout(-grid)s (currently only without nested images/assets), objects, linked collections and internationalization.
Actually, it supports querying raw texts (and any trivial field types), Markdown, Wysiwyg, images, galleries, assets, sets, repeaters, layout(-grid)s (currently only without nested images/assets), objects, linked collections and internationalization.

## Installation

Expand Down Expand Up @@ -290,6 +290,10 @@ Notes:

1. You can access the raw Markdown with this attribute.

#### Wysiwygs

Wysiwyg fields (or `What you see is what you get`) works the same way as Markdown fields, but instead of accessing an HTML equivalent through the `value → childMarkdownRemark → html` attribute, it's accessible straight through the `value` attribute.

#### Sets

The set field type allows to logically group a number of other fields together.
Expand Down
24 changes: 22 additions & 2 deletions src/CockpitService.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const mime = require('mime')
const request = require('request-promise')
const slugify = require('slugify')
const hash = require('string-hash')
const { parse } = require('node-html-parser')

const {
METHODS,
Expand Down Expand Up @@ -181,6 +182,7 @@ module.exports = class CockpitService {
nodes.forEach(node => {
node.items.forEach(item => {
this.normalizeNodeItemImages(item, existingImages)
this.normalizeNodeItemWysiwygs(item, existingImages)
this.normalizeNodeItemAssets(item, existingAssets)
this.normalizeNodeItemMarkdowns(
item,
Expand Down Expand Up @@ -241,7 +243,6 @@ module.exports = class CockpitService {
} else if (!path.startsWith('http')) {
path = `${this.baseUrl}/${path}`
}

galleryImageField.value = path
existingImages[path] = null
})
Expand All @@ -258,7 +259,6 @@ module.exports = class CockpitService {
normalizeNodeItemAssets(item, existingAssets) {
getFieldsOfTypes(item, ['asset']).forEach(assetField => {
let path = assetField.value.path

trimAssetField(assetField)

path = `${this.baseUrl}/storage/uploads${path}`
Expand All @@ -274,6 +274,26 @@ module.exports = class CockpitService {
}
}

normalizeNodeItemWysiwygs(item, existingImages) {
getFieldsOfTypes(item, ['wysiwyg']).forEach(field => {
let imgTags = parse(field.value).querySelectorAll('img')
let path
for (let tag of imgTags) {
if (
existingImages[path] != null ||
existingImages[path] === undefined
) {
if (tag.attributes.src.startsWith('/')) {
path = `${this.baseUrl}${tag.attributes.src}`
} else {
path = `${this.baseUrl}/${tag.attributes.src}`
}
}
existingImages[path] = null
}
})
}

normalizeNodeItemMarkdowns(
item,
existingImages,
Expand Down
13 changes: 11 additions & 2 deletions src/CollectionItemNodeFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@ const {
})

module.exports = class CollectionItemNodeFactory {
constructor(createNode, collectionName, images, assets, markdowns, layouts) {
constructor(
createNode,
collectionName,
images,
assets,
markdowns,
layouts,
baseUrl
) {
this.createNode = createNode
this.collectionName = collectionName
this.images = images
this.assets = assets
this.markdowns = markdowns
this.layouts = layouts
this.baseUrl = baseUrl

this.objectNodeFactory = new ObjectNodeFactory(createNode)
}
Expand All @@ -41,7 +50,7 @@ module.exports = class CollectionItemNodeFactory {
this.collectionName,
node.lang === 'any' ? node.cockpitId : `${node.cockpitId}_${node.lang}`
)
linkImageFieldsToImageNodes(node, this.images)
linkImageFieldsToImageNodes(node, this.images, this.baseUrl)
linkAssetFieldsToAssetNodes(node, this.assets)
linkMarkdownFieldsToMarkdownNodes(node, this.markdowns)
linkLayoutFieldsToLayoutNodes(node, this.layouts)
Expand Down
13 changes: 11 additions & 2 deletions src/SingletonItemNodeFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,22 @@ const {
})

module.exports = class SingletonItemNodeFactory {
constructor(createNode, singletonName, images, assets, markdowns, layouts) {
constructor(
createNode,
singletonName,
images,
assets,
markdowns,
layouts,
baseUrl
) {
this.createNode = createNode
this.singletonName = singletonName
this.images = images
this.assets = assets
this.markdowns = markdowns
this.layouts = layouts
this.baseUrl = baseUrl

this.objectNodeFactory = new ObjectNodeFactory(createNode)
}
Expand All @@ -34,7 +43,7 @@ module.exports = class SingletonItemNodeFactory {
this.singletonName,
node.lang === 'any' ? node.cockpitId : `${node.cockpitId}_${node.lang}`
)
linkImageFieldsToImageNodes(node, this.images)
linkImageFieldsToImageNodes(node, this.images, this.baseUrl)
linkAssetFieldsToAssetNodes(node, this.assets)
linkMarkdownFieldsToMarkdownNodes(node, this.markdowns)
linkLayoutFieldsToLayoutNodes(node, this.layouts)
Expand Down
22 changes: 21 additions & 1 deletion src/helpers.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { TYPE_PREFIX_COCKPIT } = require('./constants')
const { parse } = require('node-html-parser')
const hash = require('string-hash')
const { generateNodeId } = require('gatsby-node-helpers').default({
typePrefix: TYPE_PREFIX_COCKPIT,
Expand Down Expand Up @@ -32,7 +33,7 @@ function getFieldsOfTypes(item, types) {
return fieldsOfTypes
}

function linkImageFieldsToImageNodes(node, images) {
function linkImageFieldsToImageNodes(node, images, baseUrl) {
getFieldsOfTypes(node, ['image']).forEach(field => {
if (images[field.value] !== null) {
field.value___NODE = images[field.value].id
Expand All @@ -52,6 +53,25 @@ function linkImageFieldsToImageNodes(node, images) {
}
delete field.value
})

getFieldsOfTypes(node, ['wysiwyg']).forEach(field => {
const imageSources = getImageSourcesFromHtml(field.value)

imageSources.forEach(imageSource => {
if (!imageSource.startsWith('http')) {
field.value = field.value.replace(
imageSource,
images[baseUrl + imageSource].localPath
)
}
})
})
}

function getImageSourcesFromHtml(html) {
return parse(html)
.querySelectorAll('img')
.map(imgTag => imgTag.attributes.src)
}

function linkAssetFieldsToAssetNodes(node, assets) {
Expand Down