jquery datatables: render image from blob url - datatables

In a datatables column I want to display an image. The image is generated by sending the cell data to a 3rd party API that requires a POST request and returns a raw/binary png image.
What works just fine outside of datatables is:
// jquery ajax call. data is binary/raw png image
success: function ( data ) {
var image = document.getElementById(image_tag_id)
var url = window.URL || window.webkitURL;
image.src = url.createObjectURL(data);
}
This is inside a function that takes the image tags id and the data as arguments. Previously I used the tag (HTMLElement) directly but changed it to the id to play with datatables render function.
This change actually makes what I want theoretically work (came up while writing this question) with below render function:
"render": function ( data, type, row, meta ) {
if (type==="display") {
var tag_id = "image-" + meta.row;
getImage(tag_id, data);
return '<img id="' + tag_id + '">';
} else {
return data;
}
}
But this has a race condition. It assumes the returned html string always generates the tag faster than the image is fetched via ajax call (which probably always is the case but it I don't like it)
So how can I solve this issue better? Have render only create image tags and do the rest after?

Instead of getting the image in render, one can simply create a empty image tag with a class set. Then in drawCallback function, iterate over all the generated image tags and get the image via ajax call. This ensures there is no race condition.
However I went a different way and made my own service that works with GET requests. This then allows to set the src attribute of the image tags like one normally would. On top of that the images also can be cached and the source data for the image doesn't need to be transferred to the web page.

Related

Get HTML Data,HTML Tags from API in React-Native

I'm making mobile app with React-Native and i wanna get data from my API.But my API's datas , databases has html tags (you can see them in images which i shared) and some character codes because there are also Turkish characters.I already was using this API from my web site and there was no problem but when i try to get data to my react native app , it is getting data as a plain text as you see in my images.How can i get this datas without problem
It's called HTML entity. This is the code that works on browser (not on your case)
var decodeEntities = (function() {
// this prevents any overhead from creating the object each time
var element = document.createElement('div');
function decodeHTMLEntities (str) {
if(str && typeof str === 'string') {
// strip script/html tags
str = str.replace(/<script[^>]*>([\S\s]*?)<\/script>/gmi, '');
str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
element.innerHTML = str;
str = element.textContent;
element.textContent = '';
}
return str;
}
return decodeHTMLEntities;
})();
The code are copied from here HTML Entity Decode
But it only works on the browser because the browser are automatically translate the characters for you.
I don't think passing around unserialized data like this is a good idea. You might want to encode data in server side using url encode or something then decode it in the react-native side
Reference
https://www.w3schools.com/charsets/ref_utf_punctuation.asp
Actually i solved it with this : https://github.com/archriss/react-native-render-html
Thanks

Titanium - save remote image to filesystem

I'm building an app with titanium and I would like to save in the phone, the user's profile picture. In my login function, after the API response, I tried to do :
Ti.App.Properties.setString("user_picture_name", res.profil_picture);
var image_to_save = Ti.UI.createImageView({image:img_url}).toImage();
var picture = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, res.profil_picture); //As name, the same as the one in DB
picture.write(image_to_save);
And in the view in which I want to display the image :
var f = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory,Ti.App.Properties.getString("user_picture_name") );
var image = Ti.UI.createImageView({
image:f.read(),
width:200,
height:100,
top:20
});
main_container.add(image);
But the image doesn't appears. Could someone help me ?
Thanks a lot :)
There are 2 issues with your code:
1 - You cannot use toImage() method unless your image view is rendered on UI stack or simply on display. Rather you should use toBlob() method.
2 - Point no. 1 will also not work the way you are using because you cannot directly use toBlob() method until or unless the image from the url is completely loaded, means until it's shown on image view. To check when the image is loaded, use Ti.UI.ImageView onload event
But, there's another better approach to do such type of tasks.
Since you have the image url from your Login API response, you can use this url to fetch image from http client call like this:
function fetchImage() {
var xhr = Ti.Network.createHTTPClient({
onerror : function() {
alert('Error fetching profile image');
},
onload : function() {
// this.responseData holds the binary data fetched from url
var image_to_save = this.responseData;
//As name, the same as the one in DB
var picture = Ti.Filesystem.getFile(Ti.Filesystem.applicationDataDirectory, res.profil_picture);
picture.write(image_to_save);
Ti.App.Properties.setString("user_picture_name", res.profil_picture);
image_to_save = null;
}
});
xhr.open("GET", img_url);
xhr.send();
}
You don't need to manually cache remote images, because
Remote images are cached automatically on the iOS platform and, since
Release 3.1.0, on the Android platform.
[see docs here & credit to Fokke Zandbergen]
Just use the remote image url in your UI, at first access Titanium will download and cache it for you; next accesses to the same image url will actually be on the automatically cached version on local device (no code is best code)
Hth.

Get current page request url in handlebars?

Is there a way to the current request url or path in Handlebars? I need to be able to switch what parts of the theme is loaded based on paths. I've tried {{url}} ... no luck. Using latest Stencil with Cornerstone.
I had to do something like this for a project with 3 different category page layouts. Without custom category templates in Stencil, you have to get a little creative.
First, inject the handlebars URL into your category.js file using the BigCommerce's inject handlebar helper seen here. Then parse it so you get only the unique parts, then perform some logic based on what you want to do.
I used the breadcrumb li length as an indicator of how deep I was in the category tree. There is likely a better way, but this is what I thought of first, and it worked just fine.
category.html
{{inject "currentPage" category.url}}
category.js
var pageURL = this.context.currentPage;
var pageURL = pageURL.replace(/\//g," ").replace("http:","").replace("storeurl.mybigcommerce.com","").replace("storeurl.com","").trim();
var catName = pageURL.substr(0,pageURL.indexOf(' '));
console.log('pageURL = ' + pageURL);
console.log('catName = ' + catName);
console.log($('ul.breadcrumbs li').length);
if( $('ul.breadcrumbs li').length == 3 ){
if(catName == "black-decker"){
if($(".cat-img").length){
$(".page").addClass("model-list");
$(".cat-img").hide();
$(".page").append("<div class='model-wrap'><div class='model-catalog' data-reveal-id='myModal'><span class='click-larger'>Click to view larger</span></div></div>");
$(".sidebarBlock-heading").text("Select Your Model Number Below:");
$(".brand-img").each(function(){
$(this).addClass(catName);
});
} else {
$(".page").addClass("model-list");
$(".sidebarBlock-heading").text("Select Your Model Number Below:");
$(".brand-img").each(function(){
$(this).addClass(catName);
});
// make page full width
$(".page-sidebar.cf.Left").addClass("full-width");
}
}
// MORE CODE etc...

EmberJS Route to 'single' getting JSONP

I'm having trouble with EmberJS to create a single view to posts based on the ID, but not the ID of the array, I actually have a ID that comes with the json I got from Tumblr API.
So the ID is something like '54930292'.
Next I try to use this ID to do another jsonp to get the post for this id, it works if you open the api and put the id, and actually if you open the single url with the ID on it, works too, the problem is:
When, on the front page for example, I click on a link to go to the single, it returns me nothing and raise a error.
But if you refresh the page you get the content.
Don't know how to fix and appreciate some help :(
I put online the code: http://tkrp.net/tumblr_test/
The error you were getting was because the SingleRoute was being generated as an ArrayController but the json response was not an Array.
App.SingleController = Ember.ObjectController.extend({
});
Further note that the model hook is not fired when using linkTo and other helpers. This because Ember assumes that if you linked to a model, the model is assumed to be as specified, and it directly calls setupController with that model. In your case, you need to still load the individual post. I added the setupController to the route to do this.
App.SingleRoute = Ember.Route.extend({
model: function(params) {
return App.TKRPTumblr.find(params.id);
},
setupController: function(controller, id) {
App.TKRPTumblr.find(id)
.then(function(data) {
controller.set('content', data.response);
});
}
});
I changed the single post template a bit to reflect how the json response. One final change I made was to directly return the $.ajax. Ember understands jQuery promises directly, so you don't need to do any parsing.
Here is the updated jsbin.
I modified: http://jsbin.com/okezum/6/edit
Did this to "fix" the refresh single page error:
setupController: function(controller, id) {
if(typeof id === 'object'){
controller.set('content', id.response);
}else{
App.TKRPTumblr.find(id)
.then(function(data) {
controller.set('content', data.response);
});
}
}
modified the setupController, since I was getting a object when refreshing the page and a number when clicking the linkTo
Dont know if it's the best way to do that :s

How do I get data from a background page to the content script in google chrome extensions

I've been trying to send data from my background page to a content script in my chrome extension. i can't seem to get it to work. I've read a few posts online but they're not really clear and seem quite high level. I've got managed to get the oauth working using the Oauth contacts example on the Chrome samples. The authentication works, i can get the data and display it in an html page by opening a new tab.
I want to send this data to a content script.
i'm having a lot of trouble with this and would really appreciate if someone could outline the explicit steps you need to follow to send data from a bg page to a content script or even better some code. Any takers?
the code for my background page is below (i've excluded the oauth paramaeters and other )
` function onContacts(text, xhr) {
contacts = [];
var data = JSON.parse(text);
var realdata = data.contacts;
for (var i = 0, person; person = realdata.person[i]; i++) {
var contact = {
'name' : person['name'],
'emails' : person['email']
};
contacts.push(contact); //this array "contacts" is read by the
contacts.html page when opened in a new tab
}
chrome.tabs.create({ 'url' : 'contacts.html'}); sending data to new tab
//chrome.tabs.executeScript(null,{file: "contentscript.js"});
may be this may work?
};
function getContacts() {
oauth.authorize(function() {
console.log("on authorize");
setIcon();
var url = "http://mydataurl/";
oauth.sendSignedRequest(url, onContacts);
});
};
chrome.browserAction.onClicked.addListener(getContacts);`
As i'm not quite sure how to get the data into the content script i wont bother posting the multiple versions of my failed content scripts. if I could just get a sample on how to request the "contacts" array from my content script, and how to send the data from the bg page, that would be great!
You have two options getting the data into the content script:
Using Tab API:
http://code.google.com/chrome/extensions/tabs.html#method-executeScript
Using Messaging:
http://code.google.com/chrome/extensions/messaging.html
Using Tab API
I usually use this approach when my extension will just be used once in a while, for example, setting the image as my desktop wallpaper. People don't set a wallpaper every second, or every minute. They usually do it once a week or even day. So I just inject a content script to that page. It is pretty easy to do so, you can either do it by file or code as explained in the documentation:
chrome.tabs.executeScript(tab.id, {file: 'inject_this.js'}, function() {
console.log('Successfully injected script into the page');
});
Using Messaging
If you are constantly need information from your websites, it would be better to use messaging. There are two types of messaging, Long-lived and Single-requests. Your content script (that you define in the manifest) can listen for extension requests:
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
if (request.method == 'ping')
sendResponse({ data: 'pong' });
else
sendResponse({});
});
And your background page could send a message to that content script through messaging. As shown below, it will get the currently selected tab and send a request to that page.
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.sendRequest(tab.id, {method: 'ping'}, function(response) {
console.log(response.data);
});
});
Depends on your extension which method to use. I have used both. For an extension that will be used like every second, every time, I use Messaging (Long-Lived). For an extension that will not be used every time, then you don't need the content script in every single page, you can just use the Tab API executeScript because it will just inject a content script whenever you need to.
Hope that helps! Do a search on Stackoverflow, there are many answers to content scripts and background pages.
To follow on Mohamed's point.
If you want to pass data from the background script to the content script at initialisation, you can generate another simple script that contains only JSON and execute it beforehand.
Is that what you are looking for?
Otherwise, you will need to use the message passing interface
In the background page:
// Subscribe to onVisited event, so that injectSite() is called once at every pageload.
chrome.history.onVisited.addListener(injectSite);
function injectSite(data) {
// get custom configuration for this URL in the background page.
var site_conf = getSiteConfiguration(data.url);
if (site_conf)
{
chrome.tabs.executeScript({ code: 'PARAMS = ' + JSON.stringify(site_conf) + ';' });
chrome.tabs.executeScript({ file: 'site_injection.js' });
}
}
In the content script page (site_injection.js)
// read config directly from background
console.log(PARAM.whatever);
I thought I'd update this answer for current and future readers.
According to the Chrome API, chrome.extension.onRequest is "[d]eprecated since Chrome 33. Please use runtime.onMessage."
See this tutorial from the Chrome API for code examples on the messaging API.
Also, there are similar (newer) SO posts, such as this one, which are more relevant for the time being.