How to show a default preview icon in case if it's not possible to create a thumbnail? - jquery-file-upload

I am setting up Jquery-File-Upload for my website. The script is you can see here:
http://blueimp.github.io/jQuery-File-Upload/‎
This script automatically creates preview thumbnails of image files, however, it allows to select any files (doc, pdf etc). If user selects such a file, the script shows error "File type not allowed" but doesn't show any thumbnail. I want to set up a default thumbnail image for all non-image files.
I modified jquery.fileupload-image.js file:
Original:
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
}
return data;
}
My modification:
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
} else {
data.files[data.index][options.name||'preview']='<img src="/images/default-thumbnail.png">';
}
return data;
}
It works perfectly but the problem is that I will use this script in different sections of my website and thumbnail size always will be different.
So, I need to define default thumbnail in my html file. I tried:
var defaultthumbnail = '<img src="/images/default-thumbnail.png">';
or in options:
defaultthumbnail: '<img src="/images/default-thumbnail.png">'
but it doesn't work. The script doesn't return image and doesn't show any error.
Any ideas?
<script>
$(function () {
var formData = $('#fileupload').serializeArray();
var defaultthumbnail = '<img src="/images/default-thumbnail.png">';
'use strict';
$('#fileupload').fileupload({
url:'//mydomain.com'
});
$('#fileupload').fileupload('option', {
acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i,
autoUpload:false,
maxNumberOfFiles:10,
disableImageResize: /Android(?!.*Chrome)|Opera/
.test(window.navigator.userAgent)
});
if ($.support.cors) {
$.ajax({
url: $('#fileupload').fileupload('option', 'url'),
type: 'HEAD'
}).fail(function () {
$('<div class="alert alert-danger"/>')
.text('Upload server currently unavailable - ' +
new Date())
.appendTo('#fileupload');
});
}
});
</script>

Looks that Jquery-File-Upload project is abandoned...
So if you want to show a default thumbnail for unsupported file types, do the following:
<script>
var defaultthumbnail = '<img src="/images/default-thumbnail.png" />';
$(function () {
var formData = $('#fileupload').serializeArray();
'use strict';
..............
..............
</script>
in jquery.fileupload-image.js file
change
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
}
return data;
}
to
setImage:function(data,options){
if(data.preview&&!options.disabled){
data.files[data.index][options.name||'preview']=data.preview;
} else {
data.files[data.index][options.name||'preview']=defaultthumbnail;
}
return data;
}

Related

How I get contain of a href and img from cgv website using axios and jsdom

I have a problem when i wanto target and get contain a href and img from this website https://www.cgv.id/en/movies/now_playing but i always wrong to get it. This is may code:
const { default: axios } = require("axios");
const { JSDOM } = require("jsdom");
(async () => {
try {
const { data } = await axios.get(
"https://www.cgv.id/en/movies/now_playing"
);
let dom = new JSDOM(data).window.document;
let list = [...dom.getElementsByClassName('movie-list-body').querySelectorAll('li')]
list = list.map(v => v.document.querySelectorAll('li a[href]').textContent.trimEnd())
console.log(list);
} catch (error) {
console.log(error);
}
})()
My code is error. How i repair it and can target to get contain a href and img it?
There are couple of issues with using JSDOM there, especially the way you are using it.
Firstly the website in question does not have any markup for the DOM element with the class name movie-list-body as you retrieve it using Axios
On further inspection I realised they are using a jQuery AJAX call to retrieve all the links and images from a JSON file.
Following is the script they are using to do so.
<script>
$(function() {
$.ajax({
type: 'GET',
url: '/en/loader/home_movie_list',
success: function(data) {
$('.movie-list-body').html(data.now_playing);
$('.comingsoon-movie-list-body').html(data.comingsoon);
$('.lazy').lazy({
combined: true
});
}
});
});
</script>
In my opinion you should just use that JSON file. However, if you still want to use JSDOM following are some of the approaches.
Given that the site requires resource processing, if you want to parse the whole page using JSDOM you will have to pass the options as mentioned in the JSDOM documentation as follows:
const options = {
contentType: "text/html",
includeNodeLocations: true,
resources: "usable",
};
let dom = new JSDOM( data, options ).window.document;
These options will allow the JSDOM to load all the resources including jQuery that will in-turn allow the Node to make the AJAX call, populate the element and then in-theory you extract the links. However, there are some CSS files that JSDOM is unable to parse.
Therefore, I think your best bet is to do something along the following lines:
const { default: axios } = require("axios");
const { JSDOM } = require("jsdom");
(async () => {
try {
const data = await axios.get(
"https://www.cgv.id/en/loader/home_movie_list"
);
const base_url = 'https://www.cgv.id';
var dom = new JSDOM(data.data.now_playing).window.document;
var lists = [ ... dom.getElementsByTagName('ul')[0].children ]
var list = lists.map( list => [ base_url+list.firstChild.href, list.firstChild.firstChild.dataset.src ] );
console.log( list );
} catch (error) {
console.log(error);
}
})()
Note:
There is only one catch with the approach mentioned above which is that if the author of the website changes the endpoint for the JSON file, your solution will stop working.

tinyMCE editor setting localised path as src of uploaded image

I've setup tinyMCE to do image uploading and it displays uploaded images in the editor, but on inspecting the source of the editors HTML I can see that the src attribute is set like it would be a file path:
<img src="../../../api/images/1"/>
I have a file_picker_callback which POSTs the image to my backend server to save the image, and returns an absolute URL in the "location" key as specified in the tinyMCE docs: https://www.tiny.cloud/docs/configure/file-image-upload/#images_upload_url
But I am unsure why regardless of providing an absolute URL the src set on the image begins with "../../../".
The relevant tinyMCE configuration:
tinymce.init({
file_picker_types: 'file image',
file_picker_callback: function(cb, value, meta) {
let tinyMCE = this;
var input = document.createElement('input');
input.setAttribute('type', 'file');
input.setAttribute('accept', 'image/*,.doc,.docx,.txt,.rtf,.odt,.pdf');
input.onchange = function() {
var file = this.files[0];
var reader = new FileReader();
reader.onload = function () {
// Register the blob in TinyMCEs image blob registry.
var id = 'blobid' + (new Date()).getTime();
var blobCache = tinyMCE.editorUpload.blobCache;
var base64 = reader.result.split(',')[1];
var blobInfo = blobCache.create(id, file, base64);
blobCache.add(blobInfo);
backend.save(file).then(
fileLocation => {
let options = {};
if (meta.filetype == 'file') {
options = {
title: file.name,
text: 'My Attachment'
};
}
cb(fileLocation, options);
},
(/* error */) => {
blobCache.removeByUri(blobInfo.blobUri());
}
);
};
reader.readAsDataURL(file);
};
input.click();
}
});
I can see that there is an options object I can pass to the callback which sets some element attributes of the image, but I can't find a reference to what this object can contain in the docs :(
Would like some help to solve this and get absolute URLs in my image srcs, thanks
convert_urls: false,
By default all URLs are automatically converted to relative URLs. If you want to insert the real URL of the uploaded image, set convert_urls option to false. It will restore URLs to their original values.

Chrome App FileReader

I'm trying to make use of the file system API in a Chrome App. I've tried all the sample code I can find and can't get a simple text file to read. I'm logging almost every step, and what seems to happen (or not happen) is everything stops the first time I reference a file reader object. It creates just fine, because I can log the .readyState, but after that I can't seem to even set an onload()event or execute a .readAsText().
Here's what I'm calling from a button:
function clickButton(){
chrome.fileSystem.chooseEntry({type: 'openFile', acceptsMultiple: false}, function(FileEntry){
if(chrome.runtime.lastError) {console.warn("Warning: " + chrome.runtime.lastError.message);}
else{
console.log(FileEntry);
var thing = new FileReader();
console.log(thing.readyState);
thing.onloadstart(function(){
console.log("Started loading " & FileEntry);
});
console.log("added onloadstart");
console.log(thing.readyState);
console.log(thing);
thing.readAsText(FileEntry);
console.log(thing.readyState);
console.log(thing.result);
}
});
document.getElementById("status").innerHTML = "I did something";
}
I did read somewhere that Chrome doesn't allow access to local files, but the chrome apps seem to be different. At least, the documentation seems to suggest that.
The only thing I end up with in my console is the FileEntry object.
https://developer.chrome.com/apps/app_storage#filesystem
I've used the example code right from the above link and still can't get it right. Anyone else have this issue or know what I'm doing wrong?
There is a difference between a FileEntry and a File. You need to call FileEntry's .file() method. So, replace
thing.readAsText(FileEntry);
with
FileEntry.file(function(File) {
thing.readAsText(File)
})
https://developer.mozilla.org/en-US/docs/Web/API/FileEntry#File
Try this code...
<!doctype html>
<html>
<script>
function handle_files(files) {
for (i = 0; i < files.length; i++) {
file = files[i]
console.log(file)
var reader = new FileReader()
ret = []
reader.onload = function(e) {
console.log(e.target.result)
}
reader.onerror = function(stuff) {
console.log("error", stuff)
console.log (stuff.getMessage())
}
reader.readAsText(file) //readAsdataURL
}
}
</script>
<body>
FileReader that works!
<input type="file" multiple onchange="handle_files(this.files)">
</body>
</html>
I've written a function to extract text from a file.
function getFileEntryText(fileEntry) {
return new Promise(function (resolve, reject) {
fileEntry.file(function (file) {
var fileReader = new FileReader();
fileReader.onload = function (text) {
resolve(fileReader.result);
};
fileReader.onerror = function () {
reject(fileReader.error);
};
fileReader.readAsText(file);
});
});
}
You can invoke this method like so:
getFileEntryText(fileEntry).then(function(text) {
// Process the file text here
}, function(error) {
// Handle the file error here
});
One thing I'm grappling with when working with the FileSystem is that every call is asynchronous. Having multiple levels of nested callbacks can make for code that's hard to read. I'm currently working around this by converting everything I can to a Promise.
for anyone who is interested, here's my final (working) code, complete with all the console.log()'s I needed to follow all those callbacks.
var chosenEntry = null;
function clickButton(){
console.log("Button clicked");
var accepts = [{
mimeTypes: ['text/*'],
extensions: ['js', 'css', 'txt', 'html', 'xml', 'tsv', 'csv', 'rtf']
}];
chrome.fileSystem.chooseEntry({type: 'openFile', accepts: accepts}, function(theEntry) {
if (!theEntry) {
output.textContent = 'No file selected.';
return;
}
// use local storage to retain access to this file
chrome.storage.local.set({'chosenFile': chrome.fileSystem.retainEntry(theEntry)});
console.log("local data set. calling loadFileEntry");
loadFileEntry(theEntry);
console.log("loadFileEntry called, returned to clickButton()");
});
}
function loadFileEntry(_chosenEntry) {
console.log("entered loadFileEntry()");
chosenEntry = _chosenEntry;
chosenEntry.file(function(file) {
readAsText(chosenEntry, function(result) {
console.log("running callback in readAsText");
document.getElementById('text').innerHTML = result;
console.log("I just tried to update textarea.innerHTML");
});
});
console.log("added function to chosenEntry.file()");
}
function readAsText(fileEntry, callback) {
console.log("readAsText called");
fileEntry.file(function(file) {
var reader = new FileReader();
console.log("Created reader as FileReader");
reader.onload = function(e) {
console.log("called reader.onload function");
callback(e.target.result);
};
console.log("calling reader.readAsText");
reader.readAsText(file);
});
}

Image uploaded from Mobile phone to Angular is sideways or upside down

I am able to upload images from my desktop to an Angular based Web Application overlayed on SharePoint without issue, but if I upload from a Mobile phone, such as an iPhone, using the take "Take Photo or Video" or "Photo Library" function, it causes the image to be sideways when taken in portrait or upside down when taken in landscape. Here is my current upload function. Any clues/have others had the same issues uploading to Mobile Web Applications from iPhones/Mobile Phones to a SharePoint library?
Here is my upload function:
// Upload of images
$scope.upload = function () {
//console.log($scope.files);
if (document.getElementById("file").files.length === 0) {
alert('No file was selected');
return;
}
var parts = document.getElementById("file").value.split("\\");
var uploadedfilename = parts[parts.length - 1];
var basefilename = uploadedfilename.split(".")[0];
var fileextension = uploadedfilename.split(".")[1];
var currentdate = new Date();
var formatteddate = $filter('date')(new Date(currentdate), 'MMddyy-hmmssa');
var filename = basefilename + formatteddate + '.' + fileextension;
var file = document.getElementById("file").files[0];
uploadFileSync("/sites/asite", "Images", filename, file);
}
//Upload file synchronously
function uploadFileSync(spWebUrl, library, filename, file)
{
console.log(filename);
var reader = new FileReader();
reader.onloadend = function(evt)
{
if (evt.target.readyState == FileReader.DONE)
{
var buffer = evt.target.result;
var completeUrl = spWebUrl
+ "/_api/web/lists/getByTitle('"+ library +"')"
+ "/RootFolder/Files/add(url='"+ filename +"',overwrite='true')?"
+ "#TargetLibrary='"+library+"'&#TargetFileName='"+ filename +"'";
$.ajax({
url: completeUrl,
type: "POST",
data: buffer,
async: false,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"content-length": buffer.byteLength
},
complete: function (data) {
console.log(data);
},
error: function (err) {
alert('failed');
}
});
}
};
reader.readAsArrayBuffer(file);
}
The output of these is just pushed into an array for use in an Angular UI Carousel:
// Control of Image Carousel
$scope.myInterval = 0;
// Population of carousel
$scope.slides = [];
appImages.query({
$select: 'FileLeafRef,ID,Created,Title,UniqueId',
$filter: 'ReportId eq ' + $routeParams.Id + ' and DisplayinReport eq 1',
}, function (getimageinfo) {
// Data is within an object of "value"
var image = getimageinfo.value;
// Iterate over item and get ID
angular.forEach(image, function (imagevalue, imagekey) {
$scope.slides.push({
image: '/sites/asite/Images/' + imagevalue.FileLeafRef,
});
});
});
The image carousel is on page as follows:
<div style="height: 305px; width: 300px">
<carousel interval="myInterval">
<slide ng-repeat="slide in slides" active="slide.active">
<img ng-src="{{slide.image}}" style="margin:auto;height:300px">
<div class="carousel-caption">
<h4>Slide {{$index}}</h4>
<p>{{slide.text}}</p>
</div>
</slide>
</carousel>
</div>
IMPORTANT: The images are sideways and upside down upon upload to the SharePoint library, so irrespective of outputting them, they seem to be misoriented when they hit the destination library I am using as a source to display on page.
How do I upload the images so SharePoint respects the EXIF data/orientation?
It may be related to EXIF. See JS Client-Side Exif Orientation: Rotate and Mirror JPEG Images
If you want a better answer, we will need the code which show the image, and the code server side.
UPDATE : I'm not an expert at all on SharePoint, but you can found a lot about it in the SharePoint Stack Exchange. For example, https://sharepoint.stackexchange.com/questions/131552/sharepoint-rotating-pictures-in-library, should do the trick.
To sum up a little : in your case, their could be a lot of cases to study. So, I recommended you auto-correct the exif, and then permit to your user to correct it if the auto-correct was wrong. Their is a lot of tools to do that. If you want to do it server-side, look at the link above, and if you want to do it on the client side, you could use JS-Load-Image for example.

Tumblr Audio Player not loading with Infinite Scroll

I implemented infinite scroll along with masonry on this tumblr: [check revision for link]
The audio player does not appear in posts loaded through infinite scroll, instead it displays the text "[Flash 9 is required to listen to audio.]"
The Inspire Well tumblr theme (I can't post another hyperlink but you can easily google it) seems to have solved this problem through this code:
if(InspireWell.infiniteScrolling && InspireWell.indexPage){
$masonedColumn.infinitescroll({
navSelector : 'ul.page_nav', // selector for the paged navigation
nextSelector : 'ul.page_nav li.page_next a', // selector for the NEXT link (to page 2)
itemSelector : '.post', // selector for all items you'll retrieve
loadingImg : '',
donetext : 'No more pages to load.',
errorCallback: function() {
// fade out the error message after 2 seconds
//$('#infscr-loading').animate({opacity: .8},2000).fadeOut('normal');
}
},
// call masonry as a callback
function( newElements ) {
$(newElements).css({ visibility: 'hidden' });
$(newElements).each(function() {
if($(this).hasClass("audio")){
var audioID = $(this).attr("id");
var $audioPost = $(this);
$audioPost.find(".player span").css({ visibility: 'hidden' });
var script=document.createElement('script');
script.type='text/javascript';
script.src="http://assets.tumblr.com/javascript/tumblelog.js?16";
$("body").append(script);
$.ajax({
url: "http://thetestinggrounds.tumblr.com/api/read/json?id=" + audioID,
dataType: "jsonp",
timeout: 5000,
success: function(data){
$audioPost.find(".player span").css({ visibility: 'visible' });
$audioPost.find("span:first").append('<script type="text/javascript">replaceIfFlash(9,"audio_player_' + audioID + '",\'\x3cdiv class=\x22audio_player\x22\x3e' + data.posts[0]['audio-player'] +'\x3c/div\x3e\')</script>');
}
});
}
});
I tried to adapt this for my tumblr (with placeholder text to see if it was finding the correct element):
$(window).load(function(){
$('#allposts').masonry({
singleMode: true,
itemSelector: '.box'
});
$('#allposts').infinitescroll({
navSelector : "div.navigation",
nextSelector : "div.navigation a:first",
itemSelector : ".box",
debug : true
},
function( newElements ) {
$(this).masonry({ appendedContent: $( newElements ) });
$(newElements).each(function(){
if($(this).hasClass("audio")){
var audioID = $(this).attr("id");
var $audioPost = $(this);
$audioPost.find(".audio span");
var script=document.createElement('script');
script.type='text/javascript';
script.src="http://assets.tumblr.com/javascript/tumblelog.js?16";
$("body").append(script);
$.ajax({
url: "http://fuckyeahempathy.tumblr.com/api/read/json?id=" + audioID,
dataType: "jsonp",
timeout: 5000,
success: function(data){
$audioPost.find(".audio span");
$audioPost.find("span:first").append("<p>audio player not working</p>");
}
});
}
});
}
);
});
But there is no sign of the text. Any help would be greatly appreciated.
Here is a solution I came up with when I needed to implement the same functionality in the template I was creating.
In your HTML, include your AudioPlayer Tumblr tag between comments. This is to prevent loaded scripts from being called. Also add a class "unloaded" to keep track whether or not we've loaded the audio player for this post or not.
...
{block:AudioPlayer}
<div class="audio-player unloaded">
<!--{AudioPlayerBlack}-->
</div>
{/block:AudioPlayer}
...
If you look at the commented code after the page is loaded, you will notice an embed tag being passed to one of the Tumblr javascript functions. Since we commented it, it will not execute. Instead we will want to extract this string and replace the div contents with it.
Create a javascript function which will do this. This can be done with regular javascript, but to save time I will do it with jQuery since this is how I did it for my template:
function loadAudioPosts() {
// For each div with classes "audio-player" and "unloaded"
$(".audio-player.unloaded").each(function() {
// Extract the <embed> element from the commented {AudioPlayer...} tag.
var new_html = $(this).html().substring(
$(this).html().indexOf("<e"), // Start at "<e", for "<embed ..."
$(this).html().indexOf("d>")+2 // End at "d>", for "...</embed>"
);
// Replace the commented HTML with our new HTML
$(this).html(new_html);
// Remove the "unloaded" class, to avoid reprocessing
$(this).removeClass("unloaded");
});
}
Call loadAudioPosts() once on page load, then every time your infinite scrolling loads additional posts.
html
<div class="audio" id="{postID}">{AudioPlayerBlack}</div>
css
.audio {
height:30px;
overflow-y: hidden;
}
.audio span {
display:none;
}
java
setTimeout(function() {
$wall.masonry({ appendedContent: $(newElements) });
/* repair audio players*/
$('.audio').each(function(){
var audioID = $(this).attr("id");
var $audioPost = $(this);
$.ajax({
url: 'http://yoolk.tumblr.com/api/read/json?id=' + audioID,
dataType: 'jsonp',
timeout: 50000,
success: function(data){
$audioPost.append('\x3cdiv style=\x22background-color:white;height:30px\x22 class=\x22audio_player\x22\x3e' + data.posts[0]['audio-player'] +'\x3c/div\x3e');
}
});
});
}, 2000);