How to make collection path start unchangeable - netlify-cms

I have two collections, blog, and news.
Blogposts have the path: example.com/blog/blogpost1, example.com/blog/blogpost2, etc.
News have the path: example.com/news/newsa, example.com/news/newsb
I want to have all the news to start from a relative URL of /news/.
I added this:
- { label: 'Path', name: 'path', default: '/news/' }
Which makes it a default. So in the admin panel, when creating a new post or news, the beginning of the path will be already populated as /blog/ or /news/
Other users will add posts and news. I want to avoid/prevent people to remove this default path.
Unfortunately in post/news editing mode they can delete this path on purpose or by mistake.
How can I make the default path undeletable, so that editors can only add characters after /news/ but not delete the /news/ part?
I tried to add widget: 'hidden' however this makes the whole field disappear, not only the pre-populated /news/ slug

You can add widget:hidden to the object e.g.
- { label: 'Path', name: 'path', default: '/news/', widget: 'hidden' }

Related

TYPO3 11.5 - CKEditor keeps replacing specific tags on loaded HTML with non-breaking spaces

In my TYPO3 project (v11.5.20 via composer), I want the included RTE CKEditor to be able to work with - not necessarily display though - boxicons, which are formatted as simple HTML tags like this: <i class="bxs bx-bank"></i>. I made sure that the processing options of the RTE are allowing this tag, which I can confirm as both the frontend page and the network data delivered on loading the editing frame for a content element are properly including the tag.
When editing the content element though, once I switch to the source code view of CKEditor, the i tag has been replaced with a , for reasons I cannot figure out. I've read about CKEditor's Advanced Content Filter and how it processes HTML input apart from TYPO3's HTMLParser, and that it could be disabled by setting the editor.config.allowedContent option in your custom RTE preset to true, but this has no effect for me somehow. My preset looks like this, which is basically the default preset of CKEditor with some minor changes:
imports:
# - { resource: "EXT:lraffb_intern/Configuration/RTE/Processing.yaml" }
- { resource: "EXT:rte_ckeditor/Configuration/RTE/Editor/Base.yaml" }
- { resource: "EXT:rte_ckeditor/Configuration/RTE/Editor/Plugins.yaml" }
- { resource: "EXT:rte_ckeditor_image/Configuration/RTE/Plugin.yaml" }
editor:
config:
allowedContent: true
format_tags: "p;h1;h2;h3;h4;h5;pre"
toolbarGroups:
- { name: styles, groups: [ styles, format ] }
- { name: basicstyles, groups: [ basicstyles ] }
- { name: paragraph, groups: [ list, indent, blocks, align ] }
- { name: links, groups: [ links ] }
- { name: clipboard, groups: [ clipboard, cleanup, undo ] }
- { name: editing, groups: [ spellchecker ] }
- { name: insert, groups: [ insert ] }
- { name: tools, groups: [ table, specialchar, insertcharacters ] }
- { name: document, groups: [ mode ] }
justifyClasses:
- text-left
- text-center
- text-right
- text-justify
extraPlugins:
- justify
- autolink
- editorplaceholder
removeButtons:
- Anchor
- Underline
- Strike
- Styles
(Note that I've resorted to legacy RTE processing via TSConfig since some options in the custom Processing.yaml did not work reliably somehow. The TSConfig code is quite verbose so I'll provide only when required.)
Does someone know what could cause this and how to fix it?
⚠ There are several hurdles to overcome here, but everything is feasible in some form. It should be remembered that this configuration is relatively tricky, mainly because security-related issues are involved here, of course. An input of content goes through several stages of verification:
The CKEditor only allows certain content and must receive appropriate instructions.
TYPO3 also needs permission to store certain content in the database.
Content is additionally processed with a sanitizer during output in the frontend.
You can solve this as follows (tested with TYPO3 v10/v11 with CKEditor v4):
First you should always use span instead of the HTML tag i, because this would be syntactically more correct and you have less problems with the configuration.
Also, the CKEDitor converts italic to em by default.
Another common mistake when configuring the CKEditor is to use allowedContent: true.
This basically creates a security hole in the editor and makes the concept of secure input useless.
Instead, you should always explicitly allow a specific HTML tag or attribute.
You can do this with the following statement in your YAML configuration:
editor:
config:
extraAllowedContent:
# Allow class-attribute
- span(*)[class]
# Allow all attributes
#- span(*)[*]
Further note that without the help of a JavaScript plugin for the CKEditor, empty tags are generally removed, so you would have to add a space.
You can of course solve this directly with a CKEditor plugin, and give the CKEditor the following instruction:
CKEDITOR.dtd.$removeEmpty.span = 0;
If you don't or can't use JavaScript, an icon would always have to be entered with a space:
<span class="bxs bx-bank"> </span>
Depending on your configuration you might have to allow saving CSS classes in the span tag.
You do this either in PageTSconfig:
RTE.default.proc {
# Allow additional attributes in SPAN-tags on the way from RTE to DB
HTMLparser_db.tags.span.allowedAttribs := addToList(class)
}
...or in the YAML configuration of the CKEditor (Processing):
processing:
## CONTENT TO DATABASE
HTMLparser_db:
tags:
span:
allowedAttribs:
- class
Finally I can recommend a nice TYPO3 extension that does all that (and more) for you, and offers you various icon sets (including Boxicons) for use in TYPO3:
https://github.com/quellenform/t3x-iconpack
https://github.com/quellenform/t3x-iconpack-boxicons

Create a non-editable field in Strapi

I have a project that sells products.
A product can have a price and optional: new_price. I would like to be able to sort them by price/new_price combined, meaning that I would need an additional entry in the DB like "final_price". I got an idea to create a non-editable field "new_price" in Content-Type Builder/schema.json and then update that with the final price for the product on "beforeCreate" in the lifecycles.js. However, I am not sure Strapi allows that, as I haven't been able to find a resource pointing in the documentation that it can. If there is a hacky way to do it, please advise. I am open to all kinds of other suggestions on how to do this Business logic as well.
Thank you in advance.
There is a way in strapi to make the field non editable on UI. You can go to Content-type-builder-> Your component-> Configure the view. And click on the text field. You can just make editable field as false.
I see two options:
(a) Add the field and forget about it being non-editable. You can calculate the final_price on insertion of an entry in your collection with Lifecycle hooks: https://docs.strapi.io/developer-docs/latest/development/backend-customization/models.html#lifecycle-hooks.
(b) Don't add a new field, but override the controller to return an additional field: https://docs.strapi.io/developer-docs/latest/development/backend-customization/controllers.html#extending-core-controllers.
Ok, so I found a "hacky" way to do this. I don't like it, as it is not that beautiful and sophisticated, but it does the job.
In product schema.json I added a
"final_price": {
"type": "decimal"
}
In lifecycles.js, I created a new function that will calculate my final price and write it in "final_price" attribute:
module.exports = {
beforeCreate(event) {
priceCalc(event);
},
beforeUpdate(event) {
priceCalc(event);
},
};
const priceCalc = (event) => {
const { data } = event.params;
data.final_price = data.new_price ? data.new_price : data.price;
};
In the admin panel, in Content-Type Builder in Product, I clicked "Configure the view" and deleted the Final Price field from Displayed Fields section. This made the field hidden, lol.
Now I am sorting all products with sort: ['final_price:asc']
That is it.Hope it helps anyone!

Gatsby: set an image background through frontmatter, GraphQl and Styled-components

I know this problem sounds a bit complex but it's not.
I'll try my best to explain it in a simple way:
I'm making a list of blog posts for the homepage of my Gatsby website.
The list is made of "boxes", every box that links to a post has a background-image.
I pass this background-image to a styled-component, it gets the image from a prop value that I inserted in the main < div > element (you'll find the example bellow).
It works fine, till I try use an image from my local folder under src (instead of using an online link that I simply putted on frontmatter).
Here's what I did in the past, and worked:
I put the url of the image on the frontmatter of the markdown file:
---
slug: "/post/my-post"
[...]
imghero: "https:/path/to/image-online.jpg"
---
Then query it with graphql:
const LISTING_QUERY = graphql`
query BlogPostListing {
allMarkdownRemark(limit: 10, sort: {
order: DESC,
fields: [frontmatter___date]
}) {
edges {
node {
excerpt
frontmatter {
title
slug
date(formatString: "MMMM DD, YYYY")
imghero
}
}
}
}
}
`
After that I insert the {node.frontmatter.imghero} it on a prop on the main div:
const Listing = () => (
<StaticQuery
query={LISTING_QUERY}
render={({allMarkdownRemark}) => (
allMarkdownRemark.edges.map(({node}) => (
<Article img_background={node.frontmatter.imghero} key={node.frontmatter.slug}>
[... etc ...]
</Article>
))
)}
/>
)
export default Listing
And finally I call that img_background prop in the styled-component:
const Article = styled.article`
background-image: url(${props => props.img_background};);
[... etc ...]
`
This method works.
Now I want to get the image from my "images" folder and not from a random url.
I installed gatsby-remark-images
Set it on gatsby-config.js and put the path of some image on frontmatter.
Test everything with http://localhost:8000/___graphql (and worked)
Insert the additional query throught graphql:
[...]
frontmatter {
date(formatString: "DD MMMM, YYYY")
title
imghero
hero {
childImageSharp{
fluid(maxWidth: 630) {
...GatsbyImageSharpFluid
}
}
}
[...]
I modify the node on the component with the new path:
<Article img_background={node.frontmatter.hero.childImageSharp.fluid} [...]>
[...]
</Article>
Gatsby Develop compiles fine.
But then my homepage is completely white.
And the console of the browser says that node.frontmatter.hero is "null".
I don't know that else to do.
Thanks for the help.
I think a bit more info is necessary to resolve your issue, none of the thing you listed out looks wrong in itself. However so many folks got tripped off by image handling in gatsby that I'm writing a check list. It's meant to be generic, but I think no.5, 8, 9, 12 might help you locate the problem.
Using image with gatsby-transformer-remark + gatsby-transformer-sharp troubleshooting
Setup
Is there any error at all? Sometimes gatsby will still compile successfully despite something's wrong. Check the console for anything that's... red.
Did you restart gatsby i.e turn it on and off again? Try removing cache & public folder (.cache and public) if you suspect something's wrong with them.
Did you list your image folder, or any of its parent folders in gatsby-source-filesystem?
In your frontmatter, is the path to the image relative to the markdown file itself? i.e path starts with a dot ./relative/path/to/image.png
Does all markdown has a hero field in frontmatter? If a file doesn't have a hero field, it will be null.
If the image path in frontmatter is not relative or doesn't link to a file, it'll be treated as a regular string.
Query & Fragments
Does your query work? Test your query in http://localhost:8000/___graphql. Make sure the image field show up as a File node. Try something simple like
query {
allMarkdownRemark {
frontmatter {
title
hero {
id
name <-- just enough to know the file exists
}
}
}
}
If your hero shows up as a string, something's wrong, check the setup again.
Are you using fragments? Currently fragments can't be test in the graphiql tool, so you might need to find the definition of that fragment and test it manually. Here's a list of the default ones that come with gatsby-transformer-sharp and their definitions.
If you're using a custom fragment, make sure to define & export it somewhere.
Usage
If image doesn't show up in the browser, inspect & try to find what's shown up in place of your image.
Are you using gatsby-image? If so, make sure you're passing in something it can work with.
Make sure your image component receives what it should. If your component's expecting a path, don't pass in an object, like result of a fragment.
Some side note
gatsby-remark-images only handle relative links in markdown image & html <img>, so if your image is living in frontmatter, it won't do anything.

CKEditor 5 links: Set default target for links or edit target

In CKEditor 5 I don't see field for target attribute in link dialog.
How to add such field? Or set target=_blank as default.
Thanks
Since version 11.1.0 of a Link Plugin, there is added link decorator feature. This feature provides an easy way to define rules when and how to add some extra attributes to links.
There might be manual or automatic decorators.
First provides a UI switch which might be toggled by the user. When the user edits a link and toggles it, then preconfigured attributes will be added to the link e.g. target="_blank".
Second one, are applied automatically when content is obtained from the Editor. Here you need to provide a callback function which based on link's URL decides if a given set of attributes should be applied.
There is also a preconfigured decorator, which might be turn on with simple config.link.addTargetToExternalLinks=true. It will add target="blank" and rel="noopener noreferrer" to all links started with: http://, https:// or //.
You can achieve it by adding this code in CKEditor Initialization Script:
ClassicEditor
.create( document.querySelector( '#editor' ), {
// ...
link: {
decorators: {
openInNewTab: {
mode: 'manual',
label: 'Open in a new tab',
defaultValue: true, // This option will be selected by default.
attributes: {
target: '_blank',
rel: 'noopener noreferrer'
}
}
}
}
} )
.then( ... )
.catch( ... );
Here is the Documentation Link . It will be working fine.

Backbone.js: when to render views when navigating routes

Here are the requirements for my backbone app
display a list of folders that user has created
display the contents of a folder when a folder is clicked
Here is how I've implemented it.
AppRouter = Backbone.Router.extend({
routes: {
'': 'home',
'get/:name/:id': 'contents'
},
home: function() {
// show list of folders
},
contents: function(name, id) {
// show contents of clicked folder
}
});
This approach is giving me problems since when I click on a folder, the route gets saved in browser history and is of the structure 'domain.com#get/folder/1`. If I happen to paste this url in the address bar of browser, the list of folders won't be rendered since it doesn't match the route.
Would it be a smart strategy to display the list of folders in initialize function of router? may be create a page view which checks if the folders have already been displayed or not?
If I understand correctly, the list of folders should be shown permanently. And your application has two big views, the list of folders, and the contents. And the list of folders must be displayed all the time.
var AppRouter = Backbone.Router.extend({
// it's better to use REST names than custom ones
routes: {
'': 'index',
'get/:id/:name': 'show'
},
initialize: function(options) {
this.folders = new Folders(options.folders); // folders is your Backbone.Collection
// always show the FoldersView, something like
// new FoldersView({collection: this.folders, el: $('the folders container')})
},
index: function() {
// probably clear the contents area, something like
// $("#content").html('')
}
show: function(id, name) {
var folder = this.folders.get(id);
// create a view for this folder
// and render it in the content area, something like
// view = new FolderView(model: folder)
// $("#content").html(view.render().el)
}
})

Resources