I'm making a react front end to a database, I'd like to be able to upload images to a folder (which I can) and then put all of those images into a mui image list (docs here: https://mui.com/material-ui/react-image-list/).
To do this, I need to give a src for each image, but I don't necessarily know how many images or what the names of said images will be in the final website once it's live.
How can I make a loop that will both tell how many files are in a folder as well as extract the names of those files to form them into an array?
I've seen code like this:
function importAll(r) {
let images = {};
r.keys().map((item, index) => { images[item.replace('./', '')] = r(item); });
return images;
}
const images = importAll(require.context('./images', false, /\.(png|jpe?g|svg)))
But it isn't quite what I want, because this still requires knowing the file's name before you can actually use it rather than being able to just call it by an array that points to that name
Related
I want to make a product presentation page where I retrieved the addresses of the images, then I have but the address that I retrieved it but the image does not upload (the link is correct).I found some source which said that you have to use require ('../ image / name_image.jpg') when I have but the code like it works but when I used list.image (variable) it does not work
the result that i got it
the code that creates the image
get data results
file structure
Add your image folder inside the public folder: public/image/
then use <img src="/image/m1.jpg" />
You can try this and you need to declare state images with empty array, and declare the function loadImages that will load your images dynamically:
loadImages() {
lists.forEach((item, i) =>
import(item.image)
.then(image => {
this.setState(state => ({ images: [...state.images, image] }))
})
)
}
In your jsx edit this line:
src={this.state.images[index]}
or you can use:
<img src={require(../image/m1.jpg)}/>
I am trying to make a basic Instagram web scraper, both art inspiration pictures and just generally trying to boost my knowledge and experience programming.
Currently the issue that I am having is that Casper/Phantomjs can't detect higher res images from the srcset, and I can't figure out a way around this. Instagram has their srcsets provide 640x640, 750x750, and 1080x1080 images. I would obviously like to retrieve the 1080, but it seems to be undetectable by any method I've tried so far. Setting the viewport larger does nothing, and I can't retrieve the entire source set through just getting the HTML and splitting it where I need it. And as far as I can tell, there is no other way to retrieve said image than to get it from this srcset.
Edit
As I was asked for more details, here I go. This is the code I used to get the attributes from the page:
function getImages() {
var scripts = document.querySelectorAll('._2di5p');
return Array.prototype.map.call(scripts, function (e) {
return e.getAttribute('src');
});
}
Then I do the standard:
casper.waitForSelector('div._4rbun', function() {
this.echo('...found selector ...try getting image srcs now...');
imagesArray = this.evaluate(getImages);
imagesArray.forEach(function (item) {
console.log(item);
However, all that is returned is the lowest resolution of the srcset. Using this url, for example, (https://www.instagram.com/p/BhWS4csAIPS/?taken-by=kasabianofficial) all that is returned is https://instagram.flcy1-1.fna.fbcdn.net/vp/b282bb23f82318697f0b9b85279ab32e/5B5CE6F2/t51.2885-15/s640x640/sh0.08/e35/29740443_908390472665088_4690461645690896384_n.jpg, which is the lowest resolution (640x640) image in the srcset. Ideally, I'd like to retrieve the https://instagram.flcy1-1.fna.fbcdn.net/vp/8d20f803e1cb06e394ac91383fd9a462/5B5C9093/t51.2885-15/e35/29740443_908390472665088_4690461645690896384_n.jpg which is the 1080x1080 image in the srcset. But I can't. There's no way to get that item as far as I can tell. It's completely hidden.
I found a way around it in Instagram's case. Instagram puts the source picture in a meta tag within the head. So, using the code I'll paste below, you can call all of the meta tags and then sort out which one is the source picture by checking if "og:image" is retrieved.
function getImages() {
var scripts = document.querySelectorAll('meta[content]');
return Array.prototype.map.call(scripts, function (e) {
return e.getAttribute('property') + " " + e.getAttribute('content');
});
}
And this is the way to sort the meta tags into only having the original image in its native resolution.
this.echo('...found selector ...try getting image srcs now...');
imagesArray = this.evaluate(getImages);
imagesArray.forEach(function (item) {
if (typeof item == "string" && item.indexOf('og:image') > -1) {
Edit: Unfortunately this only works for single image posts on Instagram (the site I'm trying to scrape) so this unfortunately does me no goo. The values within the meta tags don't change even if you load the next image in the post. I'm leaving this up though in case anyone else could use it, but it's not ideal for my own use case.
Yes indeed PhantomJS doesn't seem to support srcset, its Webkit engine is very old.
But to be fair, all the metadata related to the page is out in the open in the HTML as JSON in window._sharedData variable.
If you want to use a headless browser (and not parse it with any server-side language) you can do this:
var imgUrl = page.evaluate(function(){
return window._sharedData.entry_data.PostPage[0].graphql.shortcode_media.display_resources[2].src;
});
https://instagram.fhen2-1.fna.fbcdn.net/vp/8d20f803e1cb06e394ac91383fd9a462/5B5C9093/t51.2885-15/e35/29740443_908390472665088_4690461645690896384_n.jpg
Solution: So my solution was to use slimerjs. If I run the js file through "casperjs --engine=slimerjs fileName.js", I can retrieve srcsets in full. So if I say use this code:
function getImgSrc() {
var scripts = document.querySelectorAll("._2di5p");
return Array.prototype.map.call(scripts, function (e) {
return e.getAttribute("srcset");
});
}
on this url (https://www.instagram.com/p/BhWS4csAIPS/?taken-by=kasabianofficial) I will get (https://instagram.flcy1-1.fna.fbcdn.net/vp/b282bb23f82318697f0b9b85279ab32e/5B5CE6F2/t51.2885-15/s640x640/sh0.08/e35/29740443_908390472665088_4690461645690896384_n.jpg 640w,https://instagram.flcy1-1.fna.fbcdn.net/vp/b4eebf94247af02c63d20320f6535ab4/5B6258DF/t51.2885-15/s750x750/sh0.08/e35/29740443_908390472665088_4690461645690896384_n.jpg 750w,https://instagram.flcy1-1.fna.fbcdn.net/vp/8d20f803e1cb06e394ac91383fd9a462/5B5C9093/t51.2885-15/e35/29740443_908390472665088_4690461645690896384_n.jpg 1080w) as the result.
This is what I wanted as it means I can scrape those 1080 images. Sorry for this messy page, but I wanted to leave my trail of steps to any of those who might be trying like me.
First question here! So, i'm at the beginning of my studies and i have searched on Google and didn't found anything about this scenario:
I'm developing a website that contains a lot of files (over 500 on the same page, it's a list of cards). If i write all the tags of those images the code will be a mess.
I would like to know if would be possible for example to create a ".txt" file with all the img tags inside it, and make a call through JavaScript or jQuery, so that they are displayed on the screen. For example:
<div class="tab-pane fade in active" role="tabpanel" id="all-cards">
<img src="../img/cards/en-gb/xln-cards/black/fatom-fleet-captain.png">
<img src="../img/cards/en-gb/xln-cards/blue/kopala-warden-of-waves.png">
<img src="../img/cards/en-gb/xln-cards/green/colossal-dreadmaw.png">
<img src="../img/cards/en-gb/xln-cards/red/bonded-horncrest.png">
<img src="../img/cards/en-gb/xln-cards/white/adanto-vanguard.png">
<img src="../img/cards/en-gb/xln-cards/multicolored/admiral-beckett-brass.png">
<img src="../img/cards/en-gb/xln-cards/artifacts/pirate's-cutlass.png">
<img src="../img/cards/en-gb/xln-cards/lands/unknow-shores.png">
</div>
Put all those on a .txt and call on that page "cards-database.html".
Thank you!
Sure, store them in a JSON file on your server:
[
"black/fatom-fleet-captain",
"blue/kopala-warden-of-waves",
"green/colossal-dreadmaw"
]
Then make a request for that file using fetch() (in my opinion, slightly shorter than $.ajax), iterate over the list and build the image tags with $.append():
fetch('list-of-images.json')
.then(response => response.json())
.then(images => {
for (let card of images) {
$('#all-cards').append(`<img src="../img/cards/en-gb/xln-cards/${card}.png">`)
}
}
})
But as Daniel noted, there is no particular advantage to doing this. In fact, you'll take a performance hit because you have to load the page, then load the list of images, then start getting the images.
A better idea is just to store the array directly in the script file that does the appending loop, like:
const images = [
"black/fatom-fleet-captain",
"blue/kopala-warden-of-waves",
"green/colossal-dreadmaw"
];
for (let card of images) {
$('#all-cards').append(`<img src="../img/cards/en-gb/xln-cards/${card}.png">`)
}
Additional:
Don't store your entries twice. I was going to propose this in the original answer but got lazy.
Just store your cards as an object whose keys are the colour, and the card names as an array within each colour:
const cards = {
"black": [
"fatom-fleet-captain"
],
"blue": [
"kopala-warden-of-waves"
],
"green": [
"colossal-dreadmaw"
]
};
Then you can get the cards of just one colour:
// Get all the black cards
for (const card of cards.black) console.log(`black/${card}.png`)
Or you can flatten the object to get all cards in one array, here I've use for...of and for...in and an extra array for clarity:
const all_cards = [];
for (let colour in cards) {
for (let card of cards[colour]) all_cards.push(`/${colour}/${card}.png`)
}
Adjust as needed.
You may be looking at that cosnt in const all_cards = [] and wondering how that could work. Note that const prevents reassignment (meaning with =) not operations like pushing to an array, or mutating object properties.
I am attempting to use JSLink ..finally.. and I am having some trouble that I cannot seem to straighten out. For my first venture down the rabbit hole I chose something super simple for use as proof of concept. So I looked up a tutorial and came up with a simple script to draw a box around the Title field of each entry and style the text. I cannot get this to work. Is there any chance you can take a look at this code for me? I used the following tokens in the JSLink box.
~sitecollection/site/folder/folder/file.js
And
~site/folder/folder/file.js
The .js file is stored on the same site as the List View WebPart I am attempting to modify. The list only has the default “Title” column.
(function () {
var overrideContext = {};
overrideContext.Templates = {};
overrideContext.Templates.Item = overrideTemplate;
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
}) ();
function overrideTemplate(ctx) {
return “<div style=’font-size:40px;border:solid 3px black;margin-bottom:6px;padding:4px;width:200px;’>” + ctx.CurrentItem.Title + “</div>”;
}
It looks as though you are attempting to override the context (ctx) item itself, where you actually just want to override the list field and the list view in which the field is displayed. Make sense?
Firstly, change overrideContext.Templates.Item to overrideContext.Templates.Fields :
(function () {
var overrideContext = {};
overrideContext.Templates = {};
overrideContext.Templates.Fields = {
// Add field and point it to your rendering function
"Title": { "View": overrideTemplate },
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(overrideContext);
}) ();
Then when the JSLink runs the renderer looks for the Title field in the List view, and applies your overrideTemplate function.
function overrideTemplate(ctx) {
return “<div style=’font-size:40px;border:solid 3px black;margin-bottom:6px;padding:4px;width:200px;’>” + ctx.CurrentItem.Title + “</div>”;
}
In terms of running multiple JSLinks on a SharePoint page, it is quite possible to run multiple JSLink scripts, they just need to be separated by the pipe '|' symbol. I use SharePoint Online a lot and I see the following formatting working all the time (sorry Sascha!).
~site/yourassetfolder/yourfilename.js | ~site/yourassetfolder/anotherfilename.js
You can run as many scripts concurrently as you want, just keep separating them with the pipe. I've seen this on prem also, however you might want to swap out '~sites' for '~sitecollection' and make sure the js files you are accessing are at the top level site in the site collection if you do so!
I have noticed when running multiple JSLinks on a list or page because they are all doing Client Side Rendering, too many will slow your page down. If this happens, you might want to consider combining them into one JSLink script so that the server only has to call one file to return to the client to do all the rendering needed for your list.
Hope this helps.
I have a TinyMCE button and it works apart from passing the data from the media gallery into a variable (to edit into the content).
I have the following:
window.on('select', function(){
var files = window.state().get('selection').toArray();
console.log(files.id);
});
which doesn't work, but if I change too:
window.on('select', function(){
var files = window.state().get('selection').toArray();
console.log(files);
});
I get "array (object)" in the console.log and by opening the object I can see id is one of the "fields" available and has a value.
The basic idea is the button (before this code) opens a media library (WordPress) and on selection of the images, it passes the ID's of the images to TinyMCE to print them (later) and the only part that's not working is the above.
Anyone able to point me in the right direction (vanilla js not my forte and first time using tinymce)
You simply have to iterate the files because there are multiple file in this array.
Try this code.
window.on('select', function(){
var files = window.state().get('selection').toArray();
var images = files;
for (var k in files) {
var file = files[k];
console.log(file.id);
}
});