Filepicker.io rendered images don't thumbnail in Twitter - filepicker.io

We're just starting to use Filepicker.io in a project and had a question about rendering thumbnails. Our first test image does not appear to be recognized by Twitter as an image. This means that all the user will see is a link instead of the thumbnail.
Is there any way around this behaviour, perhaps with some sort of custom URL or optional parameter?
UPDATE
Here's the code I'm using:
<div class="upload-image">Drop files here</div>
// init filepicker plugin
filepicker.makeDropPane($('.upload-image'), {
multiple: true,
dragEnter: function() {
$(".upload-image").html("Drop to upload").css({
'backgroundColor': "#E0E0E0",
'border': "1px solid #000"
});
console.log('enter');
},
dragLeave: function() {
$(".upload-image").html("Drop files here").css({
'backgroundColor': "#F6F6F6",
'border': "1px dashed #666"
});
},
onSuccess: function(fpfiles) {
$(".upload-image").text("Done, see result below");
$.sticky('Your file was uploaded successfully.');
console.log(JSON.stringify(fpfiles));
},
onError: function(type, message) {
// $("#localDropResult").text('('+type+') '+ message);
$.sticky('Your file was uploaded successfully.');
},
onProgress: function(percentage) {
$(".upload-image").text("Uploading ("+percentage+"%)");
}
});

One thing you can do is append a +filename.jpg to the end of the image if twitter (or really any other service) is doing a simple regex, url-based determination of whether the file is an image. For instance:
https://www.filepicker.io/api/file/JhJKMtnRDW9uLYcnkRKW and
https://www.filepicker.io/api/file/JhJKMtnRDW9uLYcnkRKW+fry.png
both point to the same content, but twitter may be happier with the second.

Related

Bootbox.js making its size a custom value throws dialogue off-center

We are using the popular Bootbox dialogue for Bootstrap 3.
We would like to make it a custom size with code such as :
bootbox.dialog({
message: $("<div>").load(href, function () {
}), //load
backdrop: true,
onEscape: false,
size:'small'
}).find(".modal-content").css("max-width", "360px");
However, if we do that, the dialogue goes off-center. Is there any way to achieve this?
Many thanks
This isn't any different than manual Bootstrap modals, in that you don't target .modal-content. The width of the dialog is (supposed to be) defined by .modal-dialog, so you have two options;
1) Update your target, like so:
bootbox.dialog({
message: $("<div>").load(href, function () {
}), //load
backdrop: true,
onEscape: false,
size:'small'
}).find(".modal-dialog").css("max-width", "360px");
2) Use the className option, and move your rule to your stylesheet:
bootbox.dialog({
message: $("<div>").load(href, function () {
}), //load
backdrop: true,
onEscape: false,
className:'custom-small'
});
/* your CSS */
.custom-small .modal-dialog {
max-width: 360px;
}
The className value is applied to the .modal container, so you'd need a descendant selector (as shown) for the width to be applied properly.
Demo jsFiddle
Unless you can guarantee the response is super fast, you probably also want to revamp how you load the dialog's message, given that $.load (or any other AJAX function) is asynchronous:
$.get(href)
.done(function (response) {
bootbox.dialog({
message: response,
backdrop: true,
onEscape: false,
className:'custom-small'
});
});

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.

Chrome apps webview tag - how to inject CSS or JS in time?

I'm writing an application which should embed specific website into a <webview> and inject some CSS and JS code to adapt this website for viewing on certain touch-sensitive device.
The problem is that I can't find a way to inject my code when page is loaded, instead the code is injected AFTER the page is rendered and, as result, all modifications become visible.
While code injection perfectly works with chrome extensions and content script (by setting run_at attribute to document_end on manifest.json, this is not the case for webviews.
This is my code:
manifest.json
{
"name": "App",
"version": "0.0.1",
"manifest_version": 2,
"app": {
"background": {
"scripts": [ "main.js" ]
}
},
"permissions": [
"webview"
]
}
main.js
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', { state: "normal" },
function(win) {
win.contentWindow.onload = function() {
var wv = this.document.querySelector('webview');
wv.addEventListener('contentload', function(e) {
this.insertCSS({ code: "body { background: red !important; }" });
});
}
}
);
});
index.html
<webview src="https://developer.chrome.com/apps/tags/webview" style="width: 100%; height: 100%;"></webview>
The same on the Gist: https://gist.github.com/OnkelTem/ae6877d2d7b2bdfea5ae
If you try this app, you will see that only after the webview is loaded and fully rendered my CSS rule is applied and the page background becomes red. In this example I use contentload webview event, but I also tried all other webview events: loadstart, loadstop, loadcommit - with no any difference.
I tried also using webview.contentWindow, but this is object is EMPTY all the time, despite documentation states it should be used.
Any ideas? Is it possible at all?
First of all, use the loadcommit event instead of the contentload event.
Second, add runAt: 'document_start' to the webview.insertCSS call (this also applies to webview.executeScript, if you ever want to use it). The implementation of executeScript is shared with the extension's executeScript implementation, but unfortunately the app documentation is incomplete. Take a look at chrome.tabs.insertCSS until the app documentation is fixed.
Here is an example that works as desired:
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', { state: 'normal' },
function(win) {
win.contentWindow.onload = function() {
var wv = this.document.querySelector('webview');
// loadcommit instead of contentload:
wv.addEventListener('loadcommit', function(e) {
this.insertCSS({
code: 'body { background: red !important; }',
runAt: 'document_start' // and added this
});
});
}
}
);
});
Note: Although the previous works, I recommend to put the script that manipulates the webview in index.html, because the resulting code is much neater.
// main.js
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('index.html', { state: 'normal' });
});
<!-- index.html -->
<webview src="https://developer.chrome.com/apps/tags/webview" style="width: 100%; height: 100%;"></webview>
<script src="index.js"></script>
// index.js
var wv = document.querySelector('webview');
wv.addEventListener('loadcommit', function() {
wv.insertCSS({
code: 'body { background: red !important; }',
runAt: 'document_start'
});
});

Use TinyMCE in an overlay (jQuery Tools-Overlay)

I want to use TinyMCE editor in a overlay dialog.. Is that possible?
I have latest version TinyMCE and Jquery Tools Overlay.
JQuery Tools Overlay: http://flowplayer.org/tools/demos/overlay/index.html
I ran into a few issues with this, apparently tinymce doesn't play nicely with hidden elements, and gets confused when you write over elements it's attached to. Anyway, got it to work by using overlay's hooks, making a synchronous js call (this is the crucial part), and detaching tinymce before closing it. Code:
$(".overlayed").overlay({
onBeforeLoad: function() {
var wrap = this.getOverlay().find(".contentWrap");
var url = this.getTrigger().attr("href");
$.ajax({
url: url,
async: false,
dataType: "html",
type: "GET",
success: function(data){
wrap.html(data);
}
})
},
onLoad: function(){
if($('#overlay .mceEditor').length > 0){
tinyMCE.execCommand('mceAddControl', false, $('.mceEditor').attr('id'));
}
},
onBeforeClose: function(){
if($('#overlay .mceEditor').length > 0){
tinyMCE.execCommand('mceFocus', false, $('.mceEditor').attr('id'));
tinyMCE.execCommand('mceRemoveControl', false, $('.mceEditor').attr('id'));
}
this.getOverlay().find(".contentWrap").html("");
}
});
Code could be more elegant but works 100% of the time ;)
Hope this helps someone!

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);