Turbolinks-ios: Metadata from web->native - ios

I'm using Turbolinks 5 on the backend, and turbolinks-ios in my iOS app.
When a page loads in a VisitableViewController, I'd like to have the native app receive (or retrieve?) some metadata from the web page, in order to offer some additional UI affordances using native code.
I know I can do this in a roundabout way by setting some <meta> tags on the server side, and then executing JS in the WKWebView and getting at the meta tags that way, but it seems like a hack.
Another option is executing a turbolinks callback message and receiving via addScriptMessageHandler, but that also seems like a hack.
Any help would be appreciated! Perhaps there is a better, sanctioned way to do this? It seems like it would be a common need.

I ended up going with my original idea with the meta tags. Then, what I do is on page load, invoke a message handler like so, passing the contents of those (filtered) meta tags to the handler:
$(function() {
if (typeof webkit != 'undefined') {
var metadata = {};
$('meta[data-scanner-app="true"]').each(function() {
metadata[$(this).attr('property')] = $(this).attr('content');
});
webkit.messageHandlers.ScannerApp.postMessage(metadata);
}
});
Then I simply intercept that handler in turbolinks, and I have the data.
Note: data-scanner-app is a data attribute I add to just the meta tags I want to include.

Related

Why is my javascript not triggering when using Turbolinks, even with the correct event listener?

I have run into these issues before, so I know I need to listen to a specific event to trigger my javascript that's rendered on a page. I'm trying the following, but when using a Turbolink to get to this page, the JS isn't working:
:javascript
$(document).on("turbolinks:load", function() {
alert('hello')
})
So whenever I type the URL, I refresh the page, or come via a redirect, this works fine. As soon as I come into the page via a (turbo)link it is not. I'm a bit lost, because this exact event listener is how I read it in the docs: https://github.com/turbolinks/turbolinks#observing-navigation-events
$(document).ready(function() {
//Your code here
});
Instead of using turbolinks:load. Did you try using this instead?

jQuery mobile issues with offline web app

I'm developing an application using jQuery mobile, that will be using HTML5 offline capabilities (cache manifest, etc).
Basic program is for on-field technicians to view/modify their orders on a tablet with no internet connection. I'm using a local browser database to store the orders.
I have an orders.html page which can view any order - but to pass a parameter to it, I can't use GET parameters, because the program is offline and I can't list every single order in the manifest.
So I have to use hash parameters - eg orders.html#o4572. But jQuery mobile doesn't play nice with this scheme - it uses hash parameters for it's own schemes. When I'm on list.html and there's a link to orders.html#o4572 - it turns the link into list.html#o4752 and stays on the same page.
I can turn off jQuery mobile's link handling by setting $.mobile.linkBindingEnabled = false; but this prevents all ajax navigation - you lose the nice transitions, and pop-up dialogs don't 'just work' anymore, you have to do them manually. And there may be other issues.
Is this the only way of getting this to work properly? I'm just starting to use jQuery mobile, so I feel like I'm missing something.
I have done something similar using the jquery-mobile-router plugin with a single page app that has a offline mode, however it should work the same for a multipage app since with a multi-page app the default behavior (ajax-enabled set to true) of JQM is that it pulls in the second page and attaches it to the DOM of the current page.
Using the JQM router you should be able to do something like this
var router;
var orderHandlerRoute = function (eventType, matchObj, ui, page, evt) {
var params = router.getParams(matchObj[1]);
//use your params to pull data from localStorage
};
router = new $.mobile.Router({
'orders.html(?:[?/](.*))?' : {handler: "orderHandler", events: 'bs'}
, {orderHandler: orderHandlerRoute }
});
You should indeed not use hash parameters for anything else than selecting pages when using jquery mobile.
The standard way to proceed is to pass your parameter with file.html?parameter=value and to retrieve the value through javascript.
You can then process this value with a js function that can for instance retrieve the data with an ajax call if you are online, or read it from local storage if you are offline.
This can be done either by binding the changepage event if you want to generate your pages dynamically based on the data associated to the parameter, or by binding the pageinit event if you want to alter the page after it has been displayed (for instance fill in form elements)
Alternatively, if the use of the cache manifest prevents you from usingthe ?parameter=value syntax, you can use the following approach:
- write your target link as file.html#pagename_itemvalue
- bind the pagechange event in order to override the default behaviour, and instead parse the target value, retrieve pagename and itemvalue, and generate/access the content you want to display. You can see an example of that on this page

Custom changePage on jquery mobile causes c.data("page") is undefined on second call

I'm trying to build some custom navigation in a dynamic application, all screens are obtained from the server and thus I registered the pagebeforechange event and execute my own function.
Everything works as I expected except when I refresh the data I destroy the dynamic pages and try to call the page I was in again using the page Id, but this second time, although my code creates the HTML for the page, jQuery Mobile throws an "c.data("page") is undefined" error.
I bind the pagebeforechange event:
$(document).bind('pagebeforechange', function(e, data) {
if(typeof data.toPage === 'string') {
appobj.dynamicPage(data.toPage, data.options);
}
});
Then in the dynamicPage method I create the HTML for my page based on Underscore.js templates and let jQuery continue changing the page:
$.get('templates/page.tpl.html', function (data) {
html = _.template(data, { /* several template parameters */});
});
page = $(html);
page.appendTo('body').page();
The idea was to use as much of jQM as possible since I'm creating the destination page and injecting it into the DOM.
When I need to update the supporting data, that I store in localStorage, I just find all dynamic pages and destroy them:
var current = $.mobile.activePage.attr('id');
$('.dynamicpage').remove();
$.mobile.changePage('#' + current
When running the application I can easily navigate between various screens/pages, even for pages that don't exist when the application starts but if the data needs to be updated (because the user added elements in the application of data in the database changed) then the removal code is executed but the old page is not regenerated ending in a white page with all the DOM contents hidden, but the page I wanted to navigate too seems to be in the DOM (at least firebug tells me so).
If I were to restart development I would probably use Backbone.js to handle my model updates and view changes but for now I'll have to use only jQM. Any suggestions? I understand that jQM is not finding my page but I don't see why since my event should be called and the page regenerated, even with the allowSamePageTransition flag set.
Regards,
Sérgio Lopes

rails 3: (probably ajax question) need embeddable a banner on a html page that pulls a different 'joke' from our app every N seconds

I've never done ajax stuff myself, and this seems like an ideal feature to add to my app to learn how to do it...
My app maintains a database of jokes.
I'd like to provide a simple way for anyone to add a small banner to the html on their webpage that will display a new joke every N seconds.
It seems the two approaches are:
1) iframe where the url/view hit by the iframe has a meta refresh tag and randomly pulls a joke each time the url is hit. But iframes can resize to fit content, and I'm not sure if browsers will refresh the contents of the iframe.
2) the right way ... ajax. But I have no idea if this is a "big" or "trivial" job for a rails 3 app, and no idea where to get started.
Any pointers on doing this would be deeply appreciated!
I'll use jQuery for this example but the overall technique should work pretty much the same with any other AJAX framework.
In your JavaScript, you'll want to use $.ajax to grab a new quote from your server and setTimeout to get periodic updates; something like this:
var n_seconds = 5; // Or whatever you want.
var timer = null;
function replace_quote() {
// Do a $.ajax call to your server.
$.ajax({
url: '/some/route',
type: 'get',
dateType: 'htm;',
success: function(data) {
// Replace the quote with the new one.
$('#quote-container').html(data);
// And restart the timer.
timer = setTimeout(replace_quote, 1000 * n_seconds);
}
});
}
replace_quote();
If you start out with an empty quote box then you can simply call replace_quote() to give it an initial value through your AJAX call.
You could also use setInterval to call your quote replacer. Then you wouldn't need to manually restart the timer with the setTimeout call but you would run the risk our updates fighting each other if an AJAX call takes longer than n_seconds.
If you still want to provide a link for updating the quote then bind the link to a JavaScript function something like this:
function manually_replace() {
clearTimeout(timer);
replace_quote();
}
Calling clearTimeout will, effectively, reset the timer when they change the quote themselves.
Then, in your Rails app, you'd add a route for /some/route and the controller would simply grab a random quote from your database and then use render :partial => 'quote' to send back just the HTML snippet for the quote without all the usual layout wrapping.
Handling AJAX requests in Rails (or any other framework) is pretty much the same as handling any other request, the only difference is that you won't send back a full page, you just send back a little piece of HTML or a blob of JSON (or XML) for the client to process and render. Hence the size difference between the client-side and server-side outlines above.

Prepending and animating text loaded via AJAX with jQuery

Old hand with Prototype, new to jQuery, and writing a simple app to get a feel for the framework (and because I want to use it). I've got an HTML fragment that I load via AJAX, and I want to stick this at the top of a div, with a slide-in transition animation.
This bit works, and does the prepending bit:
// Get the HTML fragment and stick it at the top of the containing div.
$.post("/create_new_thing", function(data) {
$('#container_div').prepend(data);
});
What I'd like to do, and can't figure out, is animate the newly added HTML fragment with a show() effect.
Any suggestions?
Try something like this...
$('#div').load('file.html').fadeIn("slow");
The load function is better suited to your needs, as it's main purpose is to load HTML from a remote file and inject it into the DOM.
Using the "post" function is better for loading a remote page using a POST request (posting data via a form and returning dynamic data based on your post request).
See below...
$.post("file.php", { name: "superuntitled", time: "2am" },
function(data){
$('#div').fadeIn("slow").append(data);
});
jQuery has no support yet for "PUT" requests. So if you really need to use a put request, I can recommend extending the jQuery functionality with a custom function that adds support for "PUT". That said, there are some work arounds! See here for more details! ... http://homework.nwsnet.de/news/9132_put-and-delete-with-jquery
This is what I use for adding a new post to the list:
success: function(data){
$("#posts-container").prepend(data).children().first().hide().show('slow');
}
This assumes the added element is wrapped in a div and is first in the #posts-container.
I am using this
$.post("yourdocument.php", {parameter:"caucana.com"}, function(data) {
$('#contiene_resultados').prepend(data);
});

Resources