Show a loader while a Meteor CollectionFS and S3 image downloads? - amazon-s3

Is there any function/hook for showing a loader while an Amazon S3 image downloads from Amazon S3 (or any image from anywhere for that matter)? I'm not currently using any CDNs or CloudFront, so my downloads can sometimes be slow. I'd like to just show a loader while the image is downloading. In my code I have:
{{#if uploadedCustomLogo}}
{{#with customLogo}}
{{#if isUploaded}}
<div class="img-wrapper">
<img src="{{this.url store='logos'}}" alt=""/>
</div>
{{else}}
{{> loading}}
{{/if}}
{{/with}}
{{/if}}
The issue is the uploading {{> loading }} loader-template runs fine, but it only lasts a fraction of a second because the actual upload is really fast. It's the download that can then take several seconds (sometimes up to twenty or so even on a small image). Is there any way to test/check if an image has been downloaded?
I used FF Inspector to see if there was a delay in the src getting set on the img tag but it gets set immediately. So the wait is really on S3... nothing changes in the DOM once it finally loads.
I'm using CollectionFS and the S3 adapter (Meteor-cfs-s3).

I figured it out. I was searching for the wrong thing on Google. The question is really how to use JQuery to listen for when an image has loaded. So you can just add your loader in your template, then hide it once the load event fires on the image. This simple code works great in Meteor:
Template.myTemplate.events({
'load #whateverImage': function(event) {
event.preventDefault();
// Hide your loader DIV (for example)
hideLoader();
},

The solution is to use has stored helper, I also had a problem figuring this one out isUploaded is to the meteor server but if you want to wait to for it to be uploaded to amazon s3 {{#if this.hasStored 'thumbs'}}
edit:
Here is my custom helper to check if it's upload & stored to amazon s3 (So I can safely create an amazon s3 url and display it to the user).
Which in my case looks like this:
uploadDoc: function () {
var fileId = Template.instance().posterData.get('fileId'); // You can ignore this, It's just how I get the file document id.
if (fileId)
return Images.findOne(fileId); // We need the file document
}
isUploadedAndStored: function (storage) {
if (this && this.copies && this.copies[storage])
return true;
}
sUrl: function () {
if (this && this.copies && this.copies.thumbs)
return 'https://s3-us-west-2.amazonaws.com/NAME/' + this.copies.thumbs.key;
}
using it like this:
{{#with uploadDoc}}
{{#if isUploadedAndStored 'thumbs'}}
<img class="attachment-thumbnail" src="{{sUrl}}">
{{else}}
{{>loading}}
{{/if}}
{{/with}}
How it works? When we subscribe to the uploaded file collection the document will not have copies and when it comes from the server it means it's actually saved on amazon s3, the this.hasStored does similar check but I found it to re-run too many times maybe need to report it to github so they can fix it.

Related

How to add image locally in a Vue?

I want to add a photo to my project, but for some reason it doesn't want to add locally
Can someone help me how to do this?
template:
<li v-for="book in books" :key="book.id">
*Some code here*
<img :src="book.image"/> <<<-----Here
</li>
script:
export default {
data() {
return{
books: [
image: "../assets/images/a-Dolls-house.jpg"
]
}
}
}
Change <img :src="book.image"/> to <img :src="require(book.image)"/>
This will work because the assets folder is not public to the browser. Meaning that when you try to call from the assets folder it cannot find the path specified because the webserver cannot find the assets folder. However by calling require we load the image from the assets folder, and convert it to a base 64 encoded image. Which can be seen by the browser as it is compiled into your chunk.
The other option you have is to move your images folder to the public directory and change your image property to image: "/images/a-Dolls-house.jpg". Then the image will be public and can be accessed from the browser. Without increases your chunk sizes, or increasing your memory overhead, as the images would be linked instead of compiled.

Access to image has been blocked by CORS only on Windows

Vue component has a photo block and the "edit" button.
<template>
<div>
<tui-image-editor ref="editor" > </tui-image-editor>
<div class="">
<img :src="img">
<button #click="edit()">Edit</button>
</div>
</div>
</template>
<script>
export default {
data() {
return {
img: "cdn.domain.shop/eaa49b02e350627622904290a83599d6.png",
};
},
methods: {
edit() {
this.$refs.editor.invoke("loadImageFromURL", this.img, "Editable image");
},
},
};
</script>
As a photo editor, I use TUI image editor. In the click handler, I pass the url to the editor by loadImageFromURL function
when I click the "edit" button in Chrome in Windows I get an error
Access to image at
'cdn.domain.shop/eaa49b02e350627622904290a83599d6.png' from origin
'example.org' has been blocked by CORS policy: No
'Access-Control-Allow-Origin' header is present on the requested
resource.
But when I do the same thing in Chrome in Ubuntu, everything works fine.
What am I doing wrong?
just add random string to url
this.$refs.editor.invoke("loadImageFromURL",this.img+'?'+Math.random(), "Editable image");
the error was due to caching in the browser
After that you have to make sure that every URL you request from Chrome and Safari uses http:// instead of https://. HTTPS retrieval will not work in these browsers at all.
some allows both http and https requests I solved it with a small regular expression that replaced our https URL string with http.
What's the quick solution ?
Add the attribute crossorigin="anonymous" in the <img> tag that displays the image before opening it in the editor.
ie: <img src="targetUri" crossorigin="anonymous" />
Explain the issue and solution
The main issue is related to caching and how the browser send the Origin header.
First you have to know that by default the browser does not send the Origin header when you load an image with the <img> tag that does not have the crossorigin="anonymous" attribute.
More info
What's happening is that the browser tries to load the image from the <img> tag before the image editor is opened, and the puts it into its cache.
So when you open the editor, it tries to load the image a second time, and you actually get a cached response of the first request that was made without the Origin header. Without this header, that cached response does not contain all the allow-control-* headers necessary to pass the CORS check, that why you get the error.
You can check this, by opening Chrome's inspector with "disable cache" checked. It should work.
The previous posts that suggested to include a parameter ?t=<random_number> had the effect to bypass the browser cache, but this solution is not possible when using pre-signed urls.
So adding crossorigin="anonymous" in the img tag should solve the problem.

Headless CMS and static pages? Content updates?

I am trying to use my first Headless CMS and I've tried both Prismic.io and Contentful.
For instance, this is the code from Contentful guide:
asyncData({ env }) {
return Promise.all([
// fetch the owner of the blog
client.getEntries({
'sys.id': env.CTF_PERSON_ID
}),
// fetch all blog posts sorted by creation date
client.getEntries({
content_type: env.CTF_BLOG_POST_TYPE_ID,
order: '-sys.createdAt'
})
])
.then(([entries, posts]) => {
// return data that should be available
// in the template
return {
person: entries.items[0],
posts: posts.items
}
})
.catch(console.error)
}
This works fine and I am able to fetch my blog posts in
<article v-for="post in posts" :key="post">
<h2>{{ post.fields.title }}</h2>
<p>{{ post.fields.content }}</p>
</article>
However, if I generate static pages with Nuxt, I understood the page will still load the latest version of the content from Contentful when live, while instead it just keeps the static content fetched on the pages when generated.
Am I missing the main point here?
Thanks
What you discovered is correct. Nuxt in its current version makes requests to the contentful API when new navigations occur. Afaik there are plans to write the data to disk during build time (e.g. Gatsby does it like that) but these are not implemented yet.
Personally, I'm running my private blog on exactly this tech stack and there is a small time window where static pages and the dynamically loaded part are different. This wasn't a bit problem for me so far. I can understand though that this could cause troubles.

Javascript Fetch: How to fix downloaded blob with weird background colours?

I regularly download images as blob and show them in the html or download the to the HD. Most of the time they show correctly. But sometimes they are loaded for 50% or with weird background colours. Like these examples (last one is normal).
Here is how I download the images. I use the aurelia-fetch-client in the aurelia framework for this.
Html:
<div css="background-image: url(${ imageUrl })"></div>
Javascript:
const blob = await this.client.fetch(`${this.endpoint}/attachments/${this.attachment.name}`,
{
method: 'GET'
}).then((x) => x.blob());
this.imageUrl = URL.createObjectURL(blob);
Any idea what is causing this? It happens randomly to images that I show in the webbrowser or download to the HD. Any help is appreciated.

How to remove Magento product details storage in browser?

In Magento 2 when we are opening multiple products it stores data of those products into window.localStorage.product_data_storage locally into the browser many of the browser that data get deleted automatically but in some of the browsers it is not getting deleted
I do have to say I opened about 200 products before this happened, but
it is never clear.
When we clear the cache of browser then it is removing that content of data from browser, but it is simply understood that the end user will not go to clear their cache every time so How we can remove this content from their browser?
Any Help will be appreciated
Thank You!
As of I understood that you wanted to remove the content from browser that Magento stores locally into every browser when you/anyone opens your site to use them at some places for example to maintain the component of knock-out js in magento like in checkout page, mini-cart, etc.
Here I have created a module to achieve this, with this module you can manage that how much content should be stored into the browsers local storage. Means the magento will store the content into local storage of browser but like if you want that data should be get deleted when the limit riches to 10-20 whatever the unit you wish Then the module will delete the content from the browser & magento will again start storing data to the local from 1 count to your desired limit.
Create a module at below location
Magento_root/app/code/{VendorName}/{ModuleName}
Create below files into it at the appropriate given location.
registration.php
etc/module.xml
view/frontend/layout/catalog_product_view.xml
view/frontend/templates/product/view/removelocal.phtml
view/frontend/web/js/removelocal.js
Here I am not putting the content of registration.php & module.xml assuming that it is already understood to you. For this answer I am taking the VendorName => Vendorname & the ModuelName => Removelocal. Here is the code of custom module.
catalog_product_view.xml
<?xml version="1.0"?>
<page layout="1column" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_configuration.xsd">
<body>
<referenceContainer name="content">
<block class="Magento\Framework\View\Element\Template" name="vendorname.removelocal.content" template="Vendorname_Removelocal::product/view/removelocal.phtml" before="-" />
</referenceContainer>
</body>
</page>
removelocal.phtml
<div class="swatch-opt" data-role="remov-local-content"></div>
<script type="text/x-magento-init">
{
"[data-role=remov-local-content]": {
"Vendorname_Removelocal/js/removelocal": {
}
}
}
</script>
removelocal.js
define([
'jquery'
], function ($){
'use strict';
$.widget('mage.removelocal', {
_init: function () {
if(window.localStorage.product_data_storage)
{
var temp = window.localStorage.product_data_storage;
var myObject = JSON.parse(window.localStorage.product_data_storage);
var count = Object.keys(myObject).length;
if(count >= 10){
window.localStorage.removeItem('product_data_storage');
}
}
}
});
return $.mage.removelocal;
});
Note: After completing please do run the below command.
php bin/magento module:enable Vendorname_Removelocal
php bin/magento setup:upgrade
php bin/magento setup:static-content:deploy -f
php bin/magento cache:flush