Display progress bar while an image gallery is loading on django template - django

I want to display a progress bar (or loading icon) while a image gallery is loading on django template.
Image gallery is having a div in the template and for that div only the progress bar should appear.
Please refer to http://www.openstudio.fr/jquery/ as I am using this gallery

Your best bet is probably to do this through JavaScript instead of trying to do much of anything in Django. You would have Django populate your JavaScript, and then have the JavaScript do your progress bar. I'll use jQuery UI for the progressbar.
Django Template:
var portfolio = {
image_count = {{ images|length }},
images = [
{% for image in images %}{
'src': "{{ image.url }}",
'title': "{{ image.title }}"
}{% if not forloop.last %},{% endif %}{% endfor %}
]
};
JavaScript:
<script>
// This helps us keep track of the progress:
var count = 0;
var updateProgress = function() {
count++;
// Calculate the % we are through the images.
progress = parseInt((count / portfolio.image_count) * 100);
// Update the progressbar.
$("#progressbar").progressbar("value", progress);
// Check if we're done.
if (progress >= 100) {
$("#progressbar").hide();
// Fire up the multimedia portfolio, per the OP.
$('#multimedia-portfolio').multimedia_portfolio({width: 800});
$("#portfolio-cont").show();
}
}
$(function() {
// Initialize the progressbar at 0%.
$("#progressbar").progressbar({value:0});
// Hide the portfolio for now.
$('#portfolio-cont').hide();
if (portfolio) {
// Loop over the images.
for (var i=0; i<portfolio.image_count; i++) {
var image = portfolio.images[i];
// Create an image, a link, an li.
// Once the image is loaded, will call updateProgress.
var img = $('<img>').attr('src', image.src)
.attr('title', image.title)
.load(updateProgress);
var a = $("<a>").attr("href", image.src)
.addClass("thickbox");
$(a).append(img);
var li = $("<li>").append(a);
// Append the li to the ul.
$('#multimedia-portfolio').append(li);
}
}
});
</script>
This is also assuming that you have this(-ish) HTML:
<div id="progressbar"></div>
<div id="portfolio-cont"><ul id="multimedia-portfolio"></ul></div>
Hope that helps you at least get some direction.

Related

Removing loading screen and spinner after all contents of the window have loaded but before iframes have finished loading

I am using a loading screen with a spinner that is displayed before all contents in the window have loaded. It works well on all pages and the window loads very fast on webpages with less content but on one of my pages, I am loading many iframes that embed youtube videos. $(window).on('load', function(){}); doesn't trigger until all contents have loaded, including iframes. That means that loading takes a long time and the loading screen with the spinner is shown long after the browser has finished loading the HTML, CSS, JS, and all images. I want to use skeleton loading for the iframes after the HTML, CSS, JS, and all images have loaded to cut down on perceived load time. Is there a way to tell that the rest of the window has fully loaded but the iframes are still loading? This is what I am currently doing to remove the loading screen with the spinner:
<html>
<head>
</head>
<div class="spinner-wrapper">
<div class="spinner">
<div class="rect1"></div>
<div class="rect2"></div>
<div class="rect3"></div>
<div class="rect4"></div>
<div class="rect5"></div>
</div>
</div>
<body>
{% for video in range(videos|length) %}
<iframe class="yvideo" src="{{ "https://www.youtube.com/embed/%s" + videos[video]}.get("url") }}"></iframe>
{% endfor %}
<script type=module src="{{ url_for('static', filename='js/video.js') }}"></script>
</body>
</html>
videos.js:
$(window).on('load', function() {
preloaderFadeOutTime = 300;
function hidePreloader() {
var preloader = $('.spinner-wrapper');
preloader.fadeOut(preloaderFadeOutTime);
}
hidePreloader();
});
There can be multiple ways to solve this issue:
One simple approach can be to keep source of iframes empty initially and dynamically set source of iframes upon window.load.
Here sample code:
<script>
$(window).on('load', function() {
document.getElementById('myIframe').src = "your URL";
document.getElementById('myIframe2').src = "your URL";
preloaderFadeOutTime = 300;
function hidePreloader() {
var preloader = $('.spinner-wrapper');
preloader.fadeOut(preloaderFadeOutTime);
}
hidePreloader();
});
</script>
<iframe id="myIframe" src="" ></iframe>
<iframe id="myIframe2" src="" ></iframe>
EDIT:
If you cannot change the video.js file but can create your own js files which can interact with html on the page then do below in your custom js file:
//your external js
// first get collection of your iframes by class
var listOfIframes = document.getElementsByClassName("yvideo");
for (let item of listOfIframes) {
item.src = ""; // set them to empty.
}
window.addEventListener("load", function() {
//once page is loaded then populate the source with your json file.
for (let item of listOfIframes) {
item.src = "URLs from JSON";
}
});
Second approach:
Instead of calling hidePreloader() only at window.load. You can also check for the rest of the items in your page that if they are loaded or not. Once they are loaded, then you can use call hidePreloader()

Preview the photo after selecting the file in Django

I can not find information on this topic. How to easily create a
preview of the photo in Django after selecting it (before saving the form). As on the video below:
https://youtu.be/HVd2v1aUED0
Is there any simple plugin that will enable this? I think that sending photos in this mode is very popular (that is, a thumbnail of the photo, before saving the whole model).
In your django template you can write a small script to display the preview of the image selected by the user.
In template:
<!-- To display image -->
<img id="myimage" src="xyz" > </div>
<!-- To upload new image -->
<input name="images" onchange="readURL(this);" type="file" accept="image/*"/>
In the same template:
<script>
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#myimage').attr('src', e.target.result);
};
reader.readAsDataURL(input.files[0]);
}
}
</script>

v-card-media with base64 image

I am creating a captcha image in ColdFusion and returning it as a REST feed with Taffy. It is then shown in Vuetify
ColdFusion / Taffy code
<cfscript>
component extends="taffy.core.resource" taffy_uri="/captcha" {
function get() hint="Sends one out" {
var captcha = CreateUUID().right(4) & DayOfWeekAsString(DayOfWeek(now())).left(1).lcase() & "!";
// This is ColdFusion
var tempFile = "ram:///#captcha#.txt";
var myImage = ImageCreateCaptcha(100, 300, captcha, "low");
ImageWriteBase64(myImage, tempFile, "png", true, true);
var myfile = FileRead(tempFile);
FileDelete(tempFile);
return rep({'status' : 'success', 'time' : GetHttpTimeString(now()),
'captcha_hash' : hash(captcha), 'captcha_image' : myFile
});
}
...
</cfscript>
It returns something like this:
{"status":"success","captcha_image":"data:image/png;base64,iVBORw0KG /d67W8EALALKJQAABBYAAAILABAYAEAILAAdr...
Vue
I can display the image via
<img :src="captcha_image" height="100px;">
Vuetify
If I don't use a height, the image does not come out at all
If I use a height like this, it comes out with the wrong aspect ratio.
<v-card-media :src="captcha_image" height="100px"></v-card-media>
Is there a work around? Or is <v-card-media the wrong tool for this?
The reason is that v-card-media use the image as a background image of a div with fixed height.
If you want to keep the aspect ratio. You can use <img /> tag with a width="100%" instead.
<img src="data:image/jpeg;base64,/9j/4AAQ..." width="100%">
demo: https://codepen.io/jacobgoh101/pen/bMrBWx?&editors=101
<div id="app">
<v-app id="inspire">
<v-layout>
<v-flex xs12 sm6 offset-sm3>
<v-card>
<img src="data:image/jpeg;base64,/9j/4AAQ..." width="100%">
<v-card-title primary-title>
...
</v-card-title>
<v-card-actions>
...
</v-card-actions>
</v-card>
</v-flex>
</v-layout>
</v-app>
</div>

Django oembed URLs for embedded tweets

I have a list of a few hundred Twitter oembed URLs but I don't know how to implement the GET requests of a list of ids in a view.
Edited - OP was using URLS, not ids.
<div class="tweets">
{% for id in ids %}
<script language="JavaScript" type="text/javascript">
$(".tweets").append(<div id="tweet" tweetID={{ id }}>)
</script>
<script sync src="https://platform.twitter.com/widgets.js"></script>
<script>
window.onload = (function(){
var tweet = document.getElementById("tweet");
var id = tweet.getAttribute("tweetID");
twttr.widgets.createTweet(
id, tweet,
{
conversation : 'none', // or all
cards : 'hidden', // or visible
linkColor : '#cc5443', // default is blue
theme : 'light' // or dark
})
.then (function (el) {
el.contentDocument.querySelector(".footer").style.display = "none";
});
});
</script>
{% endfor %}
</div>
I'm trying to loop through a list of tweet ids and embed them. How do I make the JQuery loop through to create a div for each list item?
RapydML and Rapydscript
are what I was looking for. First, I created a nodeenv env. Now, I'm rewriting the above code in pythonic javascript and pythonic html.

Django - Javascript dynamic inline FormSet with autocomplete

I'm trying to make a kind of scheduler event editor with the ability to attach participants.
Models
class Session(models.Model):
start_time = models.DateTimeField()
end_time = models.DateTimeField()
class Participation(models.Model):
session = models.ForeignKey(Session)
participant = models.ForeignKey(User)
status = models.CharField(max_length=1, choices=STATUSES)
In the editor I'd like to have an autocomplete search input from which I can find users to add to the session
Preview
Here I have typed "laurent" and I'm going to add a person by clicking on one of the resulting names
Participant colors depend on their status
I have a form for the Session object defined with start & end times
Now I think I should have an inline formset for Participations
Questions
Do you suggest that I use an inline formset for the participants ?
How can I dynamically add/delete participant rows ?
The question seems very simple but a proper response would involve several answers.
I will give my solutions point by point, using jQuery.
Autocomplete
This is the simple part. You can use a plugin like select2 or jqueryui autocomplete and a view that finds users like
def search_users(request):
search = request.GET.get('term')
users = User.objects.filter(
Q(first_name__icontains=search)
| Q(last_name__icontains=search)
)
ulist = list({'id': u.id, 'value': u'%s %s' % (u.first_name, u.last_name)}
for u in users)
return JsonResponse(ulist)
This view is compatible with the default jQuery UI Autocomplete plugin
Dynamic Formset
This is the tricky one. The key is to take advantage of management_form and form.DELETE. Here is my solution:
Use an inline formset for the participants (with one extra form)
Print the management_form
Add form lines with jQuery after autocomplete selection by cloning a hidden empty form (the extra one) and incrementing id_form-TOTAL_FORMS
Delete form lines with jQuery by hiding them and checking a hidden delete checkbox
Template
<form method="post">{% csrf_token %}
{{ sessionform }}
<div>
{{ participant_formset.management_form }}
<label for="part_search">Search: </label><input id="part_search" />
<ul id="participation_set">
{% for tform in participant_formset %}
{{ tform.id }}
<li>
<span class="participant">
{{ tform.participant }}{{ tform.instance.participant.name }}
</span>
<span class="status">{{ tform.status }}</span>
<span class="delete ui-icon ui-icon-circle-minus">
{{ tform.DELETE }}
</span>
</li>
{% endfor %}
</ul>
</div>
</form>
CSS
/* Delete button */
#participation_set .delete {
display: inline-block;
vertical-align: middle;
cursor: pointer;
}
/* Hidden delete checkbox */
#participation_set .delete input {
display: none;
}
/* Deleted form */
#participation_set li.deleted {
display: none;
}
/* Last hidden form to clone */
#participation_set li:last-child {
display: none;
}
jQuery
/*! This adds a form line
* Call it on autocomplete select
*/
function add_aform(inst, item) {
if ($(':input[name$="participant"][value=' + item.id + ']').length) {
return false;
}
var total = $('#id_' + inst + '-TOTAL_FORMS').val();
var sul = '#' + inst;
var li = $(sul + ' li:last-child');
var new_li = li.clone().appendTo(sul);
li.find('span.participant').append(item.label);
li.find(':input[name$="participant"]').val(item.id);
new_li.find(':input').each(function () {
var new_name = $(this).attr('name')
.replace('-' + (total - 1) + '-', '-' + total + '-');
$(this).attr('name', new_name);
});
new_li.find('label').each(function () {
var tmp = $(this).attr('for')
.replace('-' + (total - 1) + '-', '-' + total + '-');
$(this).attr('for', new_for);
});
new_li.find('.delete').click(del_aform);
$('#id_' + inst + '-TOTAL_FORMS').val(++total);
}
/*! This removes a form line
* Call it on click from delete buttons (placed inside each li)
*/
function del_aform() {
$(this).parents('li').addClass('deleted');
$(this).find(':checkbox').attr('checked', true);
}
I know I could also use an empty_form instance and use __prefix__ to replace the ids which simplifies the javascript for a better maintainability, but I didn't find a way to factorize the code between the true form and the empty one.
View
The view is pretty standard using inlineformset_factory with extra set to 1 (to get the only hidden form to clone). Also don't forget to use a HiddenInput widget for the field participant
This plugin would help you get the auto-complete functionality you're looking for:
https://github.com/millioner/django-ajax-select