Turbolinks not rendering code on page change - ruby-on-rails

I'm using Segment.io to do tracking on my site. We have a live chat widget that I'd like to be displayed on every page. However I'm unable to figure out how to make this work.
I've created an analytics.js which loads in the body (I've also tried adding the analytics.page(); to the body without any results):
window.analytics = window.analytics || [];
window.analytics.methods = ['identify', 'group', 'track',
'page', 'pageview', 'alias', 'ready', 'on', 'once', 'off',
'trackLink', 'trackForm', 'trackClick', 'trackSubmit'];
window.analytics.factory = function(method){
return function(){
var args = Array.prototype.slice.call(arguments);
args.unshift(method);
window.analytics.push(args);
return window.analytics;
};
};
for (var i = 0; i < window.analytics.methods.length; i++) {
var key = window.analytics.methods[i];
window.analytics[key] = window.analytics.factory(key);
}
window.analytics.load = function(key){
if (document.getElementById('analytics-js')) return;
var script = document.createElement('script');
script.type = 'text/javascript';
script.id = 'analytics-js';
script.async = true;
script.src = ('https:' === document.location.protocol
? 'https://' : 'http://')
+ 'cdn.segment.io/analytics.js/v1/'
+ key + '/analytics.min.js';
var first = document.getElementsByTagName('script')[0];
first.parentNode.insertBefore(script, first);
};
window.analytics.SNIPPET_VERSION = '3.1.0';
window.analytics.load('kYDWuP6nxI');
window.analytics.page();
document.addEventListener("turbolinks:load", function() {
console.log('page change');
analytics.page();
});
When I visit a new page on the app it shows the console log, but analytics.page(); doesn't seem to be rendered except when I do a manual page refresh.
Anybody know how to fix this?

Related

Turbolinks and 3d party plugins issue?

I have website
http://www.optimapo.ru/
and I have some 3d party scripts installed:
live chat (https://www.jivochat.com/) and yandex analitics.
But because of turbolinks they don't work properly.
For example live chat appears only on main page. But when we go to another page which is loaded using turbolinks it dissapears.
I include scripts in my code before closing body tag
<!-- BEGIN JIVOSITE CODE {literal} -->
<script type='text/javascript'>
(function(){ var widget_id = '2qq06akKwZ';var d=document;var w=window;function l(){
var s = document.createElement('script'); s.type = 'text/javascript'; s.async = true; s.src = '//code.jivosite.com/script/widget/'+widget_id; var ss = document.getElementsByTagName('script')[0]; ss.parentNode.insertBefore(s, ss);}if(d.readyState=='complete'){l();}else{if(w.attachEvent){w.attachEvent('onload',l);}else{w.addEventListener('load',l,false);}}})();</script>
<!-- {/literal} END JIVOSITE CODE -->
<!-- Yandex.Metrika counter --> <script type="text/javascript"> (function (d, w, c) { (w[c] = w[c] || []).push(function() { try { w.yaCounter39034390 = new Ya.Metrika({ id:39034390, clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ut:"noindex" }); } catch(e) { } }); var n = d.getElementsByTagName("script")[0], s = d.createElement("script"), f = function () { n.parentNode.insertBefore(s, n); }; s.type = "text/javascript"; s.async = true; s.src = "https://mc.yandex.ru/metrika/watch.js"; if (w.opera == "[object Opera]") { d.addEventListener("DOMContentLoaded", f, false); } else { f(); } })(document, window, "yandex_metrika_callbacks"); </script> <noscript><div><img src="https://mc.yandex.ru/watch/39034390?ut=noindex" style="position:absolute; left:-9999px;" alt="" /></div></noscript> <!-- /Yandex.Metrika counter -->
</body>
So what do I do to make scripts work with turbolinks?
I don't think that this is strictly possible with how the snippet you include is implemented. Let's look at it, I put it over multiple lines to make it easier to read, but this is all in there:
var s = document.createElement('script');
s.type = 'text/javascript';
s.async = true;
s.src = '//code.jivosite.com/script/widget/'+widget_id;
var ss = document.getElementsByTagName('script')[0];
ss.parentNode.insertBefore(s, ss);
If you look at turbolinks compatibility, one of the issues it reports are self loading scripts appending to head: http://reed.github.io/turbolinks-compatibility/
I don't know where document.getElementsByTagName('script')[0] lives on your page, but there's good chance it's in the head, since it's the first script on the page. Can you change to snippet to insert at the end of the body instead?
I've managed to find a solution that actually works in Turbolinks 5. I've added this piece of code s.setAttribute('data-turbolinks-track', 'reload'); in between existing code, like this:
s.type = 'text/javascript'; s.setAttribute('data-turbolinks-track', 'reload'); s.async = true;
Side note: I've also submitted a PR with this solution to Turbolinks Compatability repository
Turbolinks overrides the normal page loading process and sometimes scripts needs refresh. Here is the rails guide for using tubolinks on page load. It is coffescript. Here is javascript equivalent :
$(document).on("turbolinks:load", function() {
// your code here
});
Below code snippet works for me.
var ready;
ready = function() {
...your code ...
};
$(document).ready(ready);
$(document).on('page:load', ready);
You can try using this gem in your application:
gem 'jquery-turbolinks'
Follow the set-up instructions here.
Place your Metrika and JivoSite scripts onto the bottom of the page. You do not need to require them explicitly.
This works for me, just change
jivo_id = 'ID-MY-ACCOUNT';
Source: https://gist.github.com/Brunomm/5c227e6c254332290812
jQuery(document).on('page:load', runChat);
jQuery(document).ready(function($) {runChat();});
// Chat online jivo
function runChat(){
$('#jivo-iframe-container, .jivo_shadow, [src*="//code.jivosite"]').remove();
delete(window.jivo_api);
delete(window.jivo_config);
window.jivo_magic_var = undefined;
window.$jivosite = null;
(function(d,s){
var z = $jivosite=function(c){ z._.push(c) },
el_script = z.s = d.createElement(s),
e=d.getElementsByTagName(s)[0],
jivo_id = 'ID-MY-ACCOUNT';
z.set=function(o){
z.set._.push(o)
};
z._=[];
z.set._=[];
$.async = !0;
el_script.setAttribute("charset","utf-8");
el_script.src='//code.jivosite.com/script/widget/'+jivo_id;
z.t=+new Date;
el_script.type="text/javascript";
e.parentNode.insertBefore(el_script,e)
})(document,"script");
}

Clear rails Better Errors console

How can I clear rails web console?
Image link of better errors web console
I have developed some JavaScript that can be shoved into a bookmarklet and used in the browser to clear the live console.
Verbose Code
var consoleElements = document.querySelectorAll('.console');
var arrayLength = consoleElements.length;
if(arrayLength<1){
console.log("No consoles found to clear.");
} else {
for (var i = 0; i < arrayLength; i++) {
var consoleElement = consoleElements[i];
var consoleHistoryElement = consoleElement.querySelector('pre');
consoleHistoryElement.innerHTML = "";
consoleHistoryElement.style.backgroundColor = "#FF906F";
setTimeout(function() {
consoleHistoryElement.style.transition = "background-color 1.5s";
consoleHistoryElement.style.backgroundColor = "";
setTimeout(function() {
consoleHistoryElement.style.transition = "";
}, 1500);
}, 0);
}
console.log(arrayLength + " consoles cleared.");
}
Bookmarklet
javascript:var consoleElements=document.querySelectorAll('.console');var arrayLength=consoleElements.length;if(arrayLength<1){console.log("No consoles found to clear.");}else{for(var i=0;i<arrayLength;i++){var consoleElement=consoleElements[i];var consoleHistoryElement=consoleElement.querySelector('pre');consoleHistoryElement.innerHTML="";consoleHistoryElement.style.backgroundColor="#FF906F";setTimeout(function(){consoleHistoryElement.style.transition="background-color 1.5s";consoleHistoryElement.style.backgroundColor="";setTimeout(function() {consoleHistoryElement.style.transition = "";},1500);},0);}console.log(arrayLength + " consoles cleared.");}

Why doesn't opentok subscriber video show up in my cordova/phonegap app?

The following code works fine on a desktop browser exactly how it is, but isn't working in my phone gap/cordova app. My output says connect and iOS received stream, but nothing is showing up in the body of my app. This is in my index.js file:
var app = {
initialize: function() {
this.bindEvents();
},
bindEvents: function() {
document.addEventListener('deviceready', this.onDeviceReady, false);
},
onDeviceReady: function() {
app.receivedEvent('deviceready');
////////////////////////////////
//////Start of my opentok code////////////
var apiKey = '21692492';
var sessionId = '2_MX4yMTY5MTQ5Mn5-RnJpIEZlYiAwNyAwODozMjozOSBQU1QgMjAxNH4wLjIwMzc2MDV-';
var token = 'T1==cGFydG5lcl9pZD0yMTY5MTQ5MiZzaWc9ZWUxMTNjNjZiYjlkNWI4NTkwZTE2MDZiMjM0MzFkOWYyMzhiYzgxNjpzZXNzaW9uX2lkPTJfTVg0eU1UWTVNVFE1TW41LVJuSnBJRVpsWWlBd055QXdPRG96TWpvek9TQlFVMVFnTWpBeE5INHdMakl3TXpjMk1EVi0mY3JlYXRlX3RpbWU9MTM5MTc5MDgwNSZyb2xlPXB1Ymxpc2hlciZub25jZT0xMzkxNzkwODA1LjIzMzk0MTE4MzcyJmV4cGlyZV90aW1lPTEzOTQzODI4MDU=';
function connectedHandler(event) {
for (var i = 0; i < event.streams.length; i++) {
var newDiv = $('<div />', {id:event.streams[i].streamId});
$('body').append(newDiv);
session.subscribe(event.streams[i], event.streams[i].streamId,{});
}
}
var session = TB.initSession(sessionId);
session.addEventListener('sessionConnected', connectedHandler);
session.connect(apiKey, token);
//////End of my opentok code////////////
////////////////////////////////////////////////
},
receivedEvent: function(id) {
var parentElement = document.getElementById(id);
var listeningElement = parentElement.querySelector('.listening');
var receivedElement = parentElement.querySelector('.received');
listeningElement.setAttribute('style', 'display:none;');
receivedElement.setAttribute('style', 'display:block;');
console.log('Received Event: ' + id);
}
};
This is the output I get:
2014-02-07 11:44:19.407 HelloCordova[2377:60b] iOS Connected to Session
2014-02-07 11:44:19.408 HelloCordova[2377:60b] object for session is {
connection = {
connectionId = "4B191468-46D5-4414-A46A-5C97376D6F2E";
creationTime = 1391791459;
};
connectionCount = 0;
environment = production;
sessionConnectionStatus = OTSessionConnectionStatusConnected;
sessionId = "2_MX4yMTY5MTQ5Mn5-RnJpIEZlYiAwNyAwODozMjozOSBQU1QgMjAxNH4wLjIwMzc2MDV-";
streams = (
);
}
2014-02-07 11:44:19.456 HelloCordova[2377:60b] iOS Received Stream
Does anyone know why this isn't working and what I need to change?
Cordova plugin is modeled after OpenTok JS 2.2. In this new version, there are several changes. First of all, 'addEventListener' has been renamed to 'on'. To add events, you can do this:
session.on({
'sessionConnected': function(event){
session.publish( publisher );
},
'streamCreated': function(event){
var newDiv = $('<div />', {id:event.stream.streamId});
$('body').append(newDiv);
session.subscribe(event.stream, event.stream.streamId, {});
}
})
Note the following changes:
* addEventListener no longer exists
* on sessionConnected events, you no longer get an array of existing streams in the session. Every stream in the session will trigger a streamCreated event.
* streamCreated event callback parameter only has 1 stream element. This event will be triggered once for every stream
Here's a list of coming v2.2 changes: http://labs.tokbox.com/javascript-2.2
I have added some working sample code for you to reference: https://github.com/songz/cordova-plugin-opentok/blob/master/README.md#sample-code

Jquery mobile, How to use changePage to update changeHash and Parameters

options.dataUrl = urlObj.href;
$.mobile.changePage( $page, options );
dataUrl contains the complete url with parameters
http://example.com/#sales?p=page
but the above code only updates the url with hash only, after the new page loads... the url changes to
http://example.com/#sales
and does not apply ?p=page.
Here is the complete function, check the last few lines....
function getSPList( urlObj, options ){
var pageName = urlObj.hash.replace( /.*p=/, "" ),
pageSelector = urlObj.hash.replace( /\?.*$/, "" );
$.ajax({
url:"getSPList.php",
dataType: 'json',
data: {p: pageName},
success:function(result){
if ( result ) {
var $page = $( pageSelector ),
$header = $page.children( ":jqmData(role=header)" ),
$content = $page.children( ":jqmData(role=content)" ),
markup = "<ul data-role='listview' data-filter='true' data-filter-placeholder='Search Salesperson...'>";
for ( var i = 0; i < result.sp.length; i++ ) {
markup += "<li><a href='#addClient?p="+ result.sp[i].id +"' data-transition='slide'>" + result.sp[i].name + "</a></li>";
}
markup += "</ul>";
$content.html( markup );
$page.page();
$content.find( ":jqmData(role=listview)" ).listview();
options.dataUrl = urlObj.href;
options.changeHash = true;
$.mobile.changePage( $page, options );
}
}
});
return
}
I have experienced the same problem and here is what I've found as of version 1.3.2:
Inside $.mobile.changePage(toPage, options) options.dataUrl is passed through path.convertUrlToDataUrl() before being stored and used.
Inside path.convertUrlToDataUrl() everything before and including the '#' as well as everything after and including the '?' is stripped.
Further down inside of $.mobile.changePage() before the url is passed to $.mobile.navigate() I see this:
// rebuilding the hash here since we loose it earlier on
// TODO preserve the originally passed in path
if( !path.isPath( url ) && url.indexOf( "#" ) < 0 ) {
url = "#" + url;
}
So it seems to be a bug in jQm. For my app I'm adding this inside the bottom of the previously mentioned if statement:
var query_index = (settings.dataUrl || '').indexOf('?');
if (query_index > -1) {
url += settings.dataUrl.substring(query_index);
}
This solves the initial problem but I'm unsure about potential negative side effects or if there is a better workaround out there.

setTimeout doesn't work with addon

I'm making an addon with builder.addons.mozilla, I've posted the main.js code below. The idea is, when I click the widget of the addon, it disables a script running at panelist-webiq-cdn.appspot.com/warptest by setting the disableWebIQ variable to true. Setting the variable works, but whenever the addon is installed, the setTimeout call in the script in the page doesn't work. Does adding a PageMod to a page disable setTimeout?
The code of the button script and myScript.js doesn't do much, and myScript.js doesn't run when you click the widget anyways, so I doubt it's what's disabling setTimeout in the page.
var ss = require("simple-storage");
ss.storage.enabled = true;
ss.storage.panelIdList = [];
const widgets = require("widget");
const data = require("self").data;
var player = widgets.Widget({
id: "player",
width: 16,
label: "PanelistWebIQ",
contentURL: data.url("buttons.html"),
contentScriptFile: data.url("buttonScript.js"),
onClick: function(){
if(ss.storage.enabled){
ss.storage.enabled = false;
pageMod.destroy();
}
else{
ss.storage.enabled = true;
pageMod = pageModModule.PageMod({
include: "*",
contentScriptWhen: 'start',
contentScriptFile: data.url('myScript.js')
});
}
}
});
var pageModModule = require("page-mod");
var pageMod = pageModModule.PageMod({
include: "*",
contentScriptWhen: 'start',
contentScriptFile: data.url('myScript.js'),
onAttach: function(worker){
var url = worker.url;
var newPanelId = '';
if(url.match(/^https?:\/\/panelist-webiq-cdn.appspot.com.*panelId=.*$/)){
var pattern = 'panelId=';
var index = url.indexOf(pattern);
var sub = url.substring(index + pattern.length);
index = sub.indexOf('&');
if(index==-1){
newPanelId = sub;
}
else{
newPanelId = sub.substring(0, index);
}
}
var list = ss.storage.panelIdList;
if(newPanelId){
var matchFound = false;
for(var ctr=0; ctr<list.length; ctr++){
var panelId = list[ctr];
if(panelId==newPanelId){
matchFound = true;
break;
}
}
if(!matchFound){
list.push(newPanelId);
}
}
worker.postMessage(list + '');
}
});
Apparently, if you have an alert in your script, that alert can disable future calls to setTimeout. I removed all alerts from my addon, and it worked fine.

Resources