I have rich text generated with Twig. The text is divided into two paragraphs.
How do I create a read more function/button where the first paragraph is displayed and the second will be visible on a button click?
I thought something like this:
{% set paragraphs = content | split('</p>') %}
{% set firstParagraph = paragraphs | first ~ '</p>' %}
{% set secondParagraph = paragraphs[:2] ~ '</p>' %}
<div class="accordion-group">
<div class="accordion-heading">
<a class="accordion-toggle custom-title" data-toggle="collapse" data-parent="#accordion2" href="#collapseTwo"></a>
<p>{{ firstParagraph | raw }}</p>
</div>
<div id="collapseTwo" class="accordion-body collapse">
<div class="accordion-inner">
<p>{{ secondParagraph | raw }}</p>
</div>
</div>
<script type="text/javascript">
$(document).ready(function(){
$('.SeeMore2').click(function(){
var $this = $(this);
$this.toggleClass('SeeMore2');
if($this.hasClass('SeeMore2')){
$this.text('{{ 'Read more' | t }}');
} else {
$this.text('{{ 'Read less' | t }}');
}
});
});
</script>
<a class="SeeMore2" data-toggle="collapse" href="#collapseTwo">{{ 'Read more' | t }}</a>
The problem is that the second paragraph returns array as response.
You are using slice, which is actually using array_slice, which returns array.
If you want to get just one element then you can use php syntax:
{% set paragraphs = content | split('</p>') %}
{% set firstParagraph = paragraphs[0] ~ '</p>' %}
{% set secondParagraph = paragraphs[1] ~ '</p>' %}
Please read more about twig syntax and variables here.
Related
I am trying to create multiple dynamic load more oob buttons using Sprig plugin in Craft CMS and they are appearing properly. But the issue comes up when one button is due to be swapped with the hidden one, it results to all the load more buttons disappearing.
Here is the for loop code that I have tested:
{% for city in cities %}
{% set articleOffset = articleOffset ?? 0 %}
{% set articlesQuery = cityArticles[loop.index0].offset(articleOffset).limit(articleLimit) %}
{% set articles = articlesQuery.all() %}
<div class="filtered-bookmark mb-5">
<span> {{ city.title }}</span>
<div class="row" id="container-{{ city.slug }}">
{% for article in articles %}
{% set featureImage = article.articleFeaturedImage.one().url ?? "" %}
{% set categorySlug = article.channelsCategory.one().channel.one().slug %}
<section class="col-12 col-sm-6 col-xl-4 mb-4">
{#article card template here#}
</section>
{% endfor %}
</div>
{% if articlesQuery.count() > articles|length + articleOffset %}
<button id="{{city.slug}}-oob" sprig
s-val:articleOffset="{{ articleOffset + articleLimit }}"
s-target="#container-{{ city.slug }}"
s-select="#container-{{ city.slug }} section"
s-swap="beforeend"
{{ sprig.trigger == city.slug ~ '-oob' ? 's-swap-oob="true"' }}> View More </button>
{% else %}
<button id="{{ city.slug }}-oob" s-swap-oob="true" style="display: none"></button>
{% endif %}
</div>
{% endfor %}
Asked the question on PutYourLightsOn's Sprig GitHub and got a response. This did the trick:
<button id="{{ city.slug }}-oob" {{ sprig.trigger == city.slug ~ '-oob' ? 's-swap-oob="true"' }} style="display: none"></button>
GitHub link for reference:
https://github.com/putyourlightson/craft-sprig/issues/247
So, I'm getting the user input from a HTML textbox, and then returning some urls. But currently, when I directly return the URLS (in string), the HTML urls output aren't clickable; they're in just plaintext. Is there a way to convert the returned python strings to HTML urls?
I can change the format of the returned urls on the python side to anything that can be converted to HTML urls that's clickable.
Python code:
#this gets the query and then returns urls
#app.route('/output', methods=['POST'])
def output():
query_list = request.form['query']
outputResults = someFunction(query_list)
return render_template("output.html", output=outputResults)
HTML code:
{% extends 'layout.html' %}
{% block body %}
<div class="jumbotron text-left">
<body>
<style> p {white-space: pre-wrap; }</style>
<h1>Output</h1>
<p> {{output}}
</p>
</body>
</div>
{% endblock %}
Thanks
if you have multiple links in your query use for loop in your template like this:
{% extends 'layout.html' %}
{% block body %}
<div class="jumbotron text-left">
<body>
<style> p {white-space: pre-wrap; }</style>
<h1>Output</h1>
{% for link in output %}
title_your_link
{% endfor %}
</body>
</div>
{% endblock %}
new Flask user here...I am building a pretty file upload button for my flask app. The button essentially makes use of WTForms to validate that only csv and txt files can be uploaded. The upload works, but how can I pass validation errors to the screen as a bootstrap alert? For example:
pressing the upload button will generate an alert "no file selected"
pressing upload with a jpeg will generated "wrong file format"
any suggestions will be appreciated!
My forms.py:
class UploadForm(FlaskForm):
validators = [FileRequired(message='There was no file!'),
FileAllowed(['csv', 'txt'], message='Must be a csv file!')]
input_file = FileField('', validators=validators)
submit = SubmitField(label="Upload")
my route.py:
#app.route('/upload', methods=['GET', 'POST'])
def upload():
form = UploadForm()
if request.method == 'POST' and form.validate_on_submit():
input_file = request.files['input_file']
# Do stuff
filename = secure_filename(input_file.filename)
# save file to disk to some folder defined in a separate config file....
data = os.path.join(SOME_UPLOAD_FOLDER, filename)
input_file.save(data)
return redirect(url_for('upload'))
else:
return render_template('upload.html', form=form)
and finally the HTML/CSS/JS:
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block html_attribs %} lang="en" charset="utf-8"{% endblock %}
{% block metas %}
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
{% endblock %}
{% block styles %}
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
#browsebutton {
background-color: white;
}
#my-file-selector {
display: none;
}
</style>
{% endblock %}
{% block content %}
<div class="container">
<div class="jumbotron">
<h3>File Uploader Example</h3>
<div class="row">
<form class="form-inline center-block" action="/upload" method="POST" enctype="multipart/form-data">
{{ form.hidden_tag() }}
<div class="input-group">
<label id="browsebutton" class="btn btn-default input-group-addon" for="my-file-selector">
{{ form.input_file(id="my-file-selector") }}
Browse...
</label>
<input type="text" class="form-control" readonly>
</div>
{{ form.submit(class_="btn btn-primary") }}
</form>
</div>
</div>
</div>
{% endblock %}
{% block scripts %}
<! -- jquery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Latest compiled and minified JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"
integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
<!-- pretty upload button -->
<script>
$(function() {
// We can attach the `fileselect` event to all file inputs on the page
$(document).on('change', ':file', function() {
var input = $(this),
numFiles = input.get(0).files ? input.get(0).files.length : 1,
label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
input.trigger('fileselect', [numFiles, label]);
});
// We can watch for our custom `fileselect` event like this
$(document).ready( function() {
$(':file').on('fileselect', function(event, numFiles, label) {
var input = $(this).parents('.input-group').find(':text'),
log = numFiles > 1 ? numFiles + ' files selected' : label;
if( input.length ) {
input.val(log);
} else {
if( log ) alert(log);
}
});
});
});
</script>
{% endblock %}
If you are using WTForms, I would recommend using macros to render your form fields. It is detailed here, and you can get an example there (you can find some others online to help you customize rather than having to write it from scratch).
Note that in WTForm's documentation, the macro render_field() checks if your field has errors:
{% if field.errors %}
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
{% endif %}
You can of course decide not to use macros, in that case, you can just use this snippet above directly in your html form with form.input_file.errors instead of field.errors
I have been following the Grav documentation (https://learn.getgrav.org/cookbook/general-recipes#render-content-in-columns) to figure out how to do this, but haven't had much luck. The content for my page is in default.md, but I can't figure out to how place images and content into separate columns and rows.
I've included a screenshot of what I've created in HTML and CSS. Basically I want to put an image into the left column of a row, and details into the right column. See here: http://imgur.com/HuTSGw5
When I am editing the page template however, I only seem to have one "variable" (if that's the right word) controlling all the content. See my code for base.html.twig:
<div class="container">
<div class="row">
<div class="col-md-4">
{% block content %} {# thumbnail image goes here #}
{% endblock %}
</div> <!-- COLUMN END -->
<div class="col-md-8">
{% block content %} {# album details go here #}
{% endblock %}
</div> <!-- COLUMN END -->
</div> <!-- ROW END -->
How do I specify that a content block is specific for an image, and that another is specific for album details?
{% block content %} is the only block available when showing data from the .md file.
To render the data (text or images) in two or more columns as shown in the documentation, you have to split them in the .md file (with ---) and then use the twig function {% for %} in your .html.twig template to show them.
user/pages/my-2-column-page.md
(note the extra line before the ---)
---
title: ' 2 Columns Page'
---
Column one is for the image thumb
![the thumbnail](../my-2-column-page/thumbnail.jpg)
---
Here goes all the album details content.
Phasellus id eleifend risus. In dui tellus, dignissim id
viverra non, convallis sed ante. Suspendisse
---
user/themes/mytheme/templates/my-2-column-page.html.twig
(note the twig function {% for %} )
{% extends 'partials/base.html.twig' %}
{% block content %}
{% set colsize = [4, 8] %}
<div class="container">
<div class="row">
{% for key, column in page.content|split('<hr />') %}
<div class="col-md-{{ colsize[key] }}">
{{ column }}
</div>
{% endfor %}
</div>
</div>
{% endblock %}
OR ...
Other way to do it (more simple) is to define your .html.twig template as normal (with no "for" iteration) and call the image directly:
{% block content %}
<div class="container">
<div class="row">
<div class="col-md-4">
<img src="{{ page.media['thumbnail.jpg'].url }}" />
</div>
<div class="col-md-8">
{{ page.content }}
</div>
</div>
</div>
{% endblock %}
The image filename must match the file copied in the page folder (user/pages/my-2-column-page/thumbnail.jpg) and just type the album detail in the .md file.
I'm trying to determine which css class to give a div based on the category of a post, but I keep getting a Error: Liquid syntax error: Unknown tag on the variable that I created.
{% for post in site.posts %}
<!-- Figuring out which css class to give the cards -->
{% assign card_class = "" %}
{% if page.category == 'code' %}
{% assign card_class = "card-code" %}
{% else %}
{% assign card_class = "card-general" %}
{% endif %}
<div class="col-1-2">
<div class="paper-card {% card_class %}">
<h3>
<a class="post-link" href="{{ post.url | prepend: site.baseurl }}">{{ post.title }}</a>
</h3>
<p class="post-excerpt"><span class="post-meta">{{ post.date | date: "%b %-d, %Y" }}</span>{{ post.excerpt | strip_html }}</p>
</div>
</div>
{% endfor %}
So {% card_class %} throws an error. Is it out of scope? Is there a way to get that value into the class attribute?
The tag syntax({% if t in toto %} or {% comment %}) is not appropriate to output.
You need to use the output syntax {{ card_class }}.