Trying to include assets (js, img, css) in a drupal 8 module - html

I have a drupal module called chess, in which I have different images to be displayed, javascripts to be included, and css to be linked.
I tried defining a chess/chess.libraries.yml that looks like this:
chess:
version: 1.x
css:
theme:
css/chess.css: {}
js:
js/jquery-ui.min.js: {}
js/jquery.ui-touch-punch.min.js: {}
js/jquery.simulate.js: {}
js/chess.js: {}
js/socket.io.js: {}
js/chess-socket.js: {}
js/chat.js: {}
dependencies:
- core/jquery
and included a line {{ attach_library('chess/chess') }} in chess/templates/index.html.twig. The images live in chess/images. Additionally, my ChessController's render array looks like this:
public function page(){
$content = readfile('modules/chess/templates/index.html.twig');
$element = array (
'#type' => 'markup',
'#markup' => $this->t($content),
'#attached' => array(
'library' => 'chess/chess'
),
);
return $element;
}
So it has the chess library attached. The only thing that shows up though is the html with broken images, no css, and an error message at the bottom of the page:
The website encountered an unexpected error. Please try again later.
InvalidArgumentException: $string ("7864") must be a string. in
Drupal\Core\StringTranslation\TranslatableMarkup->__construct() (line
133 of core/lib/Drupal/Core/StringTranslation/TranslatableMarkup.php).
As far as I can tell, none of the translation modules are even enabled. Anyone got an idea of what I'm missing?
Update:
I changed the page() function of my controller to read
public function page(){
$content = readfile('modules/chess/templates/page.html.twig');
$element = array (
'#type' => 'markup',
'#template' => $content,
'#attached' => array(
'library' => 'chess/chess'
),
);
return $element;
}
and the css shows up, but the images don't yet. The source also still shows the asset function, instead of the filled in script tag.
Update 2:
I installed symfony/asset via composer, and my twig file now looks like this:
<link href="{{ asset('css/chess.css') }}" rel="stylesheet">
<script type="text/javascript" src="{{ asset('js/jquery-1.12.min.js') }}"></script>
...
<div class="piece black queen" id="black-queen"><img src="{{ asset('images/queen-black.png') }}" /></div>
The css shows up, but the content is displayed above the rest of the drupal page. Is there a way to put the page in its proper place within the drupal layout? (Also, the images aren't showing).
Update 3:
I removed all src="{{ asset(...) }}" tags from page.html.twig, and the javascript seems to work, as does the css. The only things left are how to get the page to work within the framework of the drupal page (instead of above it), and how to include images.

I think you should change it to just
{{ attach_library('chess/chess') }}
Rather than the absolute path to a CSS file.

Related

how to attach image using v-for in vue 3

im trying to make a set of images using v-for loop, but somehow it doesn't recognise variables inside the tag. pic is broken and alt just shows me {{ item.alt }} thing.
Here is my HTML:
<section class="our-technologies__section" v-for="(item, index) in tech_item" :key="index">
<div class="technologies__logo" #click="activeIndex = index" :class="{active: activeIndex === index}">
<img src="{{ item.src }}" alt="{{ item.alt }}">
<p>{{item.title}}</p>
</div>
</section>
And here are script:
export default {
name: "OurTechnologies",
data: function () {
return{
tech_item: [
{ title: 'Twilio', text: 'gfmds/lgkmlk/f', src: '../../images/twilio.png', alt: 'Twilio' },
{ title: 'Android', text: '12334356676', src: '../../images/android.png', alt: 'Android' },
],
activeIndex: 0,
}
},
}
I tried to use <img :src="item.src" :alt="item.alt"> and its still no results.
In vue cli you should use require to load the image :
<img :src="require(item.src)" :alt="item.alt"/>
<img :src="item.src" :alt="item.alt"> should work ™, but then I don't know enough about the environment you have set up. I quickly tried with a fresh project using vite and using the App component (so that it was root level), it didn't even need require for it to work. For this to work your images would be usually be in the ./src/assets/ directory, which they are not and I'm wondering if that's what is causing the problems, that the images are falling out of scope. You likely have a different setup, but I think you might able to use another option.
Place the images into the ./public/images/ folder. This will make them included as part of the bundle whether you're using dev/serve or build. Then reference them as /images/*.png without require or import. As long as you are serving the app at root level so that /images resolves correctly this should make it work. Otherwise it may need a bit of extra finessing to target the right directory.

CKEditor - HTML code keep adding new line very time I switch between source code view and wysiwyg view?

I tried to keep my jinja code in CKEditor as it was after I toggle the view between code view and WYSIWYG view.
And I could get this result by adding below line in my config.js file
CKEDITOR.config.protectedSource.push(/\r|\n/g);
CKEDITOR.config.autoParagraph = false;
However, it does not work well for HTML code. For instance, if jinja code and html mixed together like this:
{% if name=='bob' %}
{{'hello bob'}}
{%else%}
{{ 'hello ' + name }}
{% endif %}
<p>Hello visitor</p>
Here is Demo on Fiddle JS
After this, when I change from code view to wyiwyg view in CKEditor, the HTML code just increase by one new line, and another new line for another toggle view as shown below:
I can't find what is wrong with HTML code, I just what to format jinja code only, how can I fix it? Thanks
Write these additional lines under your code
$("body").on("click", ".cke_button__source", ()=>{
// if(CKEDITOR.instances.editor1.mode==="source"){
let vtk = CKEDITOR.instances.editor1.getData();
// vtk = vtk.replace(/\n<p>/gm, "<p>");
vtk = vtk.replace(/^\s*[\r\n]/gm, "");
$(".cke_source").val(vtk)
// }
})
Here is jsFiddle

React dangerouslySetInnerHTML not working when using variable

I'm creating an SPA using React that searches data and displays results. Each result follows the following model
{
"title": "A Title",
"body": " <li>escaped html&nbsp;<strong>that sould be rendered</strong>.</li>
</ul>"
}
The body property is always an escaped html that should be rendered in a component. This component looks like this:
Code
function SearchResult({ title, body, favourite }) {
return (
<article className="SearchResult">
<section>
<i className={`icon-star${favourite ? ' marked' : ''}`} />
{title}
</section>
<section
dangerouslySetInnerHTML={{ __html: body }}
className="SearchResult-body"
/>
</article>
);
}
but the body of each result is not being rendered correctly, instead, it shows the html as a text
The issue is that it only happens when I create the component passing a variable to the body property
results.map((result, index) => (
<SearchResult key={index} title={result.title} body={result.body} />
))
But if I do this, it works fine
<SearchResult
title="A title"
body=" <li>escaped html&nbsp;<strong>that sould be rendered</strong>.</li>
</ul>"
/>
Why is this different? Is there any preprocessing that I should add to the value before passing it in the property that is added by default when I use the fixed value?
Demo
A demo of this issue can be seen here
It seems like this issue only occurs when you give it an escaped html.
A solution implemented by #sergiotapia involves creating a helper function to unescape the html string to make it work.
htmlDecode(content) {
let e = document.createElement('div');
e.innerHTML = content;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
}
<section
dangerouslySetInnerHTML={{ __html: htmlDecode(body) }}
className="SearchResult-body"
/>
However as #brigand mentioned and I'll quote "Unescaping it could allow for XSS attacks and incorrect rendering." so this might not be the perfect solution for this.
See working example

Displaying HTML Body on a page using ReactJS

Say I have the following code in my database (user input):
<html>
<title>Test</title>
<body>testing website</body>
</html>
And I fetched it correctly from my database using ReactJS. How can I display this in say: 'localhost:3000/play'? I don't want it to be rendered as raw data just like the code but I want it to actually render the html body as a website. (Title set to Test, and displays a small text: testing website). How can I do that in ReactJS? I already have /play configured and I just want to know how to display it there in the index.js file. I tried something like <div dangerouslySetInnerHTML={template} /> but it didn't work.
So, I fixed it with the following:
In a separate function:
db.getHTMLBody(key).then(snapshot => {
this.setState({ body: snapshot.val() })
})
then in the render:
<div dangerouslySetInnerHTML={{ __html: this.state.body }} />
Please try :
const innerHtml = { __html: escape(snapshot.val()) }
return(<div dangerouslySetInnerHTML={innerHtml} />)

reactjs dangerouslySetInnerHTML and dynamically adding classes to links

I'm new to reactjs and working on a project that is pushing json data to the template.
json structure
"description" : "Some text with a link and another link",
I propose using the following on the template
<p className='paragraph-margin-bottom-10 text--font-size-14 paragraph--justified' dangerouslySetInnerHTML={{ __html: lang.privacy[0].description }} />
but in terms of the output - I would maybe need to append a set of classes to ALL links. What is the best practice for this
so the links render with the following
<a class="text--font-size-14 hyperlink-primary" href="#">link</a>
I can imagine that many people will not agree with me. You can actually do this. But you shouldn't. It is bad enough that you want to use dangerouslySetInnerHTML. It is possible to parse html but there are many edge cases that you would need to handle.
Either tell your backend that they should return the links with proper classes or target the links inside the description directly with css.
See some similar question like: Using regular expressions to parse HTML: why not?
Using regular expressions to parse HTML: why not?
This is how I would do it. I will write the regex later if you run into some problems. I don't have much time to spare right now. Hope it will help. :)
import React from 'react';
import { render } from 'react-dom';
const htmlFromApi = 'some html from API'
const attachClassesToLinks = (htmlWithLinks) => {
// do something special
return htmlWithLinks
}
const App = () => (
<div>
<h1>My Component</h1>
<p dangerouslySetInnerHTML={{ __html: attachClassesToLinks(htmlFromApi) }} />
</div>
);
render(<App />, document.getElementById('root'));