I have added the Google Translate plugin to my web page. How can I get a callback to my JavaScript function whenever the user selects a language from the drop down menu that the plugin adds to my web page? The Google Translate API documentation does not seem to have any information on this. I have read through the JavaScript code of the Google Translate plugin and I cannot see anything that is helpful.
It will also be fine if I get a callback to my function just before the translation of my web page begins or just after the translation of my web page ends or just before or after the translation of any specific element in my web page.
Here is the HTML for a simplified version of my web page:
<html>
<head>
</head>
<body>
<!-- Google Website Translator plugin -->
<div id="google_translate_element"></div><script type="text/javascript">
function googleTranslateElementInit() {
new google.translate.TranslateElement({pageLanguage: 'en', includedLanguages: 'es', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
<div>
<p>This part can be translated using the Google Translator plugin.</p>
</div>
<script type="text/javascript">
function translationCallback() {
// This function needs to be called when Google translates this web page.
alert("A language was selected from the Google Translator plugin dropdown");
}
</script>
</body>
</html>
Thanks for the responses. Based on the answers and comments in the SO questions referenced in the above responses, I cobbled together the code below which works for me.
I added a hidden div and a listener for its DOMSubtreeModified event. The listener gets called when Google translates the contents of the hidden div. However the listener gets called multiple times for each time a language is selected from the plugin drop down menu. Google seems to be making multiple passes. The original value of the innerHTML seems to be retained as a substring in all the passes except the last. So I check for the original innerHTML substring in the event handler to avoid executing the code multiple times.
Select an initial value for the innerHTML that is distinct for each language in the drop down menu. 'English' works in my case.
<html>
<head>
</head>
<body>
<!-- Google Website Translator plugin -->
<div id="google_translate_element"></div><script type="text/javascript">
function googleTranslateElementInit() {
new google.translate.TranslateElement({pageLanguage: 'en', includedLanguages: 'es', layout: google.translate.TranslateElement.InlineLayout.SIMPLE}, 'google_translate_element');
}
</script>
<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>
<div>
<p>This part can be translated using the Google Translator plugin.</p>
</div>
<div id="translationDetector" style="display:none;">English</div>
<script type="text/javascript">
var origValue = document.getElementById("translationDetector").innerHTML;
document.getElementById("translationDetector").addEventListener("DOMSubtreeModified", translationCallback, false);
function translationCallback() {
// This function needs to be called when Google translates this web page.
var currentValue = document.getElementById("translationDetector").innerHTML;
if (currentValue && currentValue.indexOf(origValue) < 0) {
origValue = currentValue;
alert("There is a disturbance in the force: " + currentValue);
}
}
</script>
</body>
</html>
Google translate js uses a cookie to keep track of the current language selection. You could set up a timeout to watch for changes to the cookie.
Here's how I implemented this for Drupal, adaptable to any javascript framework:
Drupal.exampleLanguageChanged = function() {
if (Drupal.exampleGetCookie('googtrans') != cookieValue) {
cookieValue = Drupal.exampleGetCookie('googtrans');
console.log('cookie changed ' + cookieValue);
}
setTimeout(Drupal.exampleLanguageChanged, 500);
};
Drupal.exampleGetCookie = function(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length >= 2) {
return parts.pop().split(";").shift();
}
return '';
};
Drupal.behaviors.exampleSimpleTranslation = {
attach: function(context) {
cookieValue = Drupal.exampleGetCookie('googtrans');
console.log('cookie value ' + cookieValue);
setTimeout(Drupal.exampleLanguageChanged, 500);
}
};
From this SO question, this code apears to work:
var $textfield = find("#google-translate");
var $popup = find("#google_translate_element");
var $select = $popup.find("select");
$textfield.click(function () {
$popup.fadeIn("fast");
return false;
});
$select.bind("change", function () {
$popup.fadeOut("fast");
});
Here's one solution, but I'm not sure if I like it that much. Essentially you check to see if the text or page has changed then when it does you act on that.
Google Translate Widget - Translation complete callback
Related
First things first, I'm brand new to Javascript and Regex. I've only been dipping my toes in this past month. I've been trying to put together away to paste a url into a text input then automatically trim it down to just the host name and validate it before I'm able to push the button.
I've gotten it working a few different times but I keep running into the same issue: After a certain period of time, it simply stops working.
I've reformatted and cleaned up the code a few times (though, I'm sure it's still very sloppy because I'm new at this) and I can get it working again. But after an hour or so of working, it stops working. Reloading the page doesn't make a difference. Even restarting my computer doesn't make a difference. It simply stops working.
My only guess is that there must be something about the way I'm going about this which is causing it crash or stall out. Perhaps a formatting issue, perhaps the methodology altogether is flawed. I just don't know enough to be able to diagnose it yet.
Hopefully, some of you nice people would be able to point out my flaws or point me in the right direction of how to fix this. I've searched and I couldn't find anyone who was trying to do the things I'm doing all in one build (preparing to myself to be proved wrong here).
Here's the code:
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<title>Untitled Document</title>
</head>
<body>
<input id="notesUrlInput" type="text" placeholder="URL Goes here" pattern="^(?!www\.)[a-zA-Z0-9\-]+\.[a-zA-Z0-9]+$" autocomplete="off">
<button id="notesExecuteButton" disabled>Execute</button>
<span id="notesUrlOutput"></span>
<!------------------------------------------------------------------------------->
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Include all compiled plugins (below), or include individual files as needed -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.5/js/bootstrap.min.js"></script>
<script>
(function () {
var timeout = null;
var notesUrlOutput = document.getElementById("notesUrlOutput");
var notesExecuteButton = document.getElementById("notesExecuteButton");
document.getElementById('notesUrlInput').addEventListener('keyup',
function (e) {
clearTimeout(timeout);
timeout = setTimeout(
function () {
rawInput = $('#notesUrlInput').val();
cleanInput = rawInput.replace('www.', '');
cleanInput = cleanInput.replace('http://', '');
cleanInput = cleanInput.replace('https://', '');
cleanInput = cleanInput.replace(/\/.*/,'');
$('#notesUrlInput').val(cleanInput);
if (cleanInput.value == "") {
notesUrlOutput.innerHTML = "";
notesExecuteButton.disabled = true; return false;
} else if(!notesUrlInput.checkValidity()) {
notesUrlOutput.innerHTML = "Invalid URL: Please provide a valid URL";
notesExecuteButton.disabled = true; return false;
} else {
notesUrlOutput.innerHTML = "Input OK";
notesExecuteButton.disabled = false; return false;
}
}, 400);
});
})();
</script>
</body>
</html>
Frustratingly, when I pasted this code in here and ran it, it worked. As soon as I opened the file I copied this from in my browser. It stopped working. I just don't understand it.
From your code it looks like you want to extract just the domain name from the input field.
You mix JavaScript DOM calls and jQuery, which is fine. It is usually easier to interact with the DOM using just jQuery. Here is your code rewritten in jQuery:
const cleanRegex = /^https?:\/\/(?:www\.)?(.*)\/.*$/;
const validRegex = /^[\w\-]+(\.[\w]+)+$/;
(function () {
$('#notesExecuteButton').prop('disabled', true);
$('#notesUrlInput').on('input', function(event) {
let val = $(this).val();
let cleaned = val.replace(cleanRegex, '$1');
$(this).val(cleaned);
if(!cleaned) {
$('#notesUrlOutput').text('');
$('#notesExecuteButton').prop('disabled', true);
} else if(!cleaned.match(validRegex)) {
$('#notesUrlOutput').text('Invalid URL: Please provide a valid URL');
$('#notesExecuteButton').prop('disabled', true);
} else {
$('#notesUrlOutput').text('Input OK');
$('#notesExecuteButton').prop('disabled', false);
}
});
})();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.0.0/jquery.min.js"></script>
<input id="notesUrlInput" />
<button id="notesExecuteButton" style="disabled: disabled;">Go</button>
<div id="notesUrlOutput"></div>
Explanation:
.on('input') - fires every time something changes in the input field- val.replace(cleanRegex, '$1') - clean up: strip protocol and www prefix, and URL path (any text after domain
cleaned.match(validRegex) - check validity of domain
.prop('disabled', true/false) - add/remove disable property
I'm a newbie with JavaScript and I asked a question earlier and got answers which helped me, but I thought I could incorporate it into the larger form I was working with and now I'm stuck again.
I have a large form with one select option. When the form is filled out, a new window opens and incorporates the values submitted into an invitation type page.
Everything else is working except for this select option. The problem I am having is depending on the selection, I want different text to be written into the new window (as part of the overall new window invitation page).
I'm really close, mostly b/c of help I received earlier today -- I can either get the new window to show just my named option value or I can get a whole new window with the different text (that is not part of the invitation page). I just can't combine the two.
I wrote up a smaller page in case someone wants to take a look at it. Thanks in advance.
<!doctype html>
<html>
<head>
<title>JavaScript Forms</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="mystyle.css">
<script type="text/JavaScript">
function newWindow() {
allInfo = open("", "displayWindow");
allInfo.document.open();
allInfo.document.write('<!doctype html><html><head><link rel="stylesheet" type="text/css" href="mystyle_invite.css"><title>Resume</title><meta charset="utf-8"> </head><body>');
allInfo.document.write(document.getElementById ('firstname').value);
allInfo.document.write('</body></html>');
allInfo.document.close();
}
function showName() {
var doIt=document.getElementById('firstname').value;
if ( doIt == "Michael" ) {
allInfo.document.write("Mr. " + doIt); //only "Mikey" is written out
}
else if ( doIt == "Sam" ) {
allInfo.document.write("Mrs. " + doIt);
}
else {
allInfo.document.write("Sir " + doIt);
}
}
</script>
</head>
<body>
<script type="text/JavaScript">
</script>
<form id="infoForm" method="post" name="infoForm">
<p>First Name:</p>
<p><select id="firstname" onChange="showName()" >
<option value="Mikey">nickname1</option>
<option value="Sammy">nickname2</option>
<option value="Sir Doug">nickname3</option>
</select></p>
<p> <input type="button" value="Submit Information" onClick="newWindow()"></p>
</form>
</body>
</html>
There are somethings that can help a lot here. First opening a second window can be a painful experience both for the user and the programmer. Unless you have an absolute need I would recommend manipulating the current window's DOM to display a popup instead.
Next if you can use DOM methods to change the page contents. document.write comes with a lot of problems which in your case are not apparent. Mainly it can erase you current DOM. You don't notice this in your example because the new window is blank so rewriting it is incidental.
Finally your use of allInfo is a quirky way to reference a global variable. It is not easily understood that this is happening from the style of code. In fact any linter will throw an error for your use of the global and will case an error if you declare "use strict" in your functions. Best to learn the good coding practises way.
Since we will want to interact with a variable (allInfo) in your case we should encapsulate the value in an object. This object can hold the state of that reference and offer some abstracted interactions with it. By doing so you avoid polluting the global name space and allow you to swap out your implementation without having to rewrite the parts of your program that depend on it.
// Our welcome window object
function WelcomeWindow() {
// save a reference to the content of your new window
// to be printed when ready. (Lazy execution)
this.innerHTML = '';
}
WelcomeWindow.prototype.open = function() {
this.win = window.open("", "displayWindow");
return this;
};
WelcomeWindow.prototype.close = function() {
this.win.close();
return this;
};
WelcomeWindow.prototype.write = function(html) {
this.innerHTML += '' + html;
return this;
};
WelcomeWindow.prototype.render = function() {
if (!this.win) { throw new Error("window has not been opened yet."); }
this.win.open();
this.win.write('<!doctype html><html><head><link rel="stylesheet" type="text/css" href="mystyle_invite.css"><title>Resume</title><meta charset="utf-8"> </head><body>');
this.win.write(this.innerHTML);
this.win.write('</body></html>');
this.win.close();
return this;
};
This allows us to declaratively manipulate the window before it is opened. For example if we want to add the name to the window:
function NameField(id) {
this.element = document.getElementById(id);
}
NameField.prototype.toString = function() {
var name = this.element.value;
switch (name) {
case 'Michael': return 'Mr. Michael';
case 'Sam': return 'Mrs. Sam';
default: return 'Sir ' + name;
}
};
NameField.prototype.toHtml = function() {
return '<strong>' + this.toString() + '</strong>';
};
Linking it together using code instead because adding events into the DOM only confuses the separation of markup and code.
window.onload = function() {
var form = document.getElementById('infoForm');
form.onsubmit = function(e) {
e.preventDefault();
var name = new NameField('firstName');
new WelcomWindow()
.write(name.toHtml())
.open()
.render();
return false;
};
};
I need to pass some text from the current page to a popup window without going for a server hit. The information (herewith represented by 90) is already available in the parent form (it's like a paragraph-long text which is stored in a hidden variable). I just need to display that as a popup.
Here's what I've tried, this works to some extent but doesn't work if I pass text, instead of a number. My second concern is that the solution kinda looks ugly. Any tips? Thank you.
This is SCCE, you can run it straight in your machine.
<html>
<head>
<title>A New Window</title>
<script type="text/javascript">
var newWindow;
var data;
function makeNewWindow(param) {
data = param;
if (!newWindow || newWindow.closed) {
newWindow = window.open("","sub","status,height=200,width=300");
setTimeout("writeToWindow()", 50); /* wait a bit to give time for the window to be created */
} else if (newWindow.focus) {
newWindow.focus( ); /* means window is already open*/
}
}
function writeToWindow() {
var k = data;
alert(data);
var newContent = "<html><head><title>Additional Info</title></head>";
newContent += "<body><h1>Some Additional Info</h1>";
newContent += "<scr"+"ipt type='text/javascript' language='javascript'> var localVar; localVar = "+ k +"; document.write('localVar value: '+localVar);</scr"+"ipt>";
newContent += "</body></html>";
// write HTML to new window document
newWindow.document.write(newContent);
newWindow.document.close( ); // close layout stream
}
</script>
</head>
<body>
<form>
<input type="button" value="Create New Window" onclick="makeNewWindow('90');" />
</form>
</body>
</html>
Actually, I googled and saw some other approach that uses window.opener.document.forms.element, but here, the window has to know in advance what it has to read from the parent. I need to be able to pass it as it will vary:
<textarea rows="15" name="projectcontent" id="projectcontent" cols="87"></textarea>
<b>View Content</b>
<head>
<title>View Project Content</title>
</head>
<body>
<img src="/images/toplogo.jpg"><br/>
<script language="Javascript">
document.write(window.opener.document.forms['yourformname'].elements['projectcontent'].value)
</script>
<img src="/images/bottomlogo.jpg">
</body>
</html>
use window.opener
From Mozilla Developer Network:
When a window is opened from another window, it maintains a reference
to that first window as window.opener. If the current window has no
opener, this method returns NULL.
https://developer.mozilla.org/en-US/docs/Web/API/window.opener
This way you can have on your original window a callback, and you can notify the window it's load and ready, rather than wait a random delay...
you add a function on the original window:
window.popupReady = function (callbackToPopup) {
callbackToPopup(newData);
}
then the popup can tell the parent window it's ready and pass it a callback to update it with data..
and on the popup try something like:
window.dataReady(newData)
{
alert(newData);
}
document.addEventListener("load", function() { window.opener.popupReady (dataReady); }
I didn't test this code, but I would take such a path as this should ensure the popupWindow is ready for you and is along the spirit of JavaScript.
In your onclick attribute you pass '90' to the function, but the function isn't set up to take an argument. So, change the first line of your function like this:
function writeToWindow(data) {
You don't need the global var data; or the local var k = data;, so get rid of them.
And instead of + k + write + data +.
That should do get your data passed.
Use this code, it works perfectly in all browsers .
#desc = parent text area id
#desc_textarea = popup
$("#desc_textarea").val(window.opener.$("#desc").val())
Thanks for reading!
I am using a WebView to show a mobile website. There is a page.html which does the AJAX xmlHttpRequest.responseText to fetch the page content.
I see the entire website except two sections displaying ads.
<div class="top-banner" class="top-rule">
<div id="hp_leaderboard" class="adContainer">
<script language="javascript" type="text/javascript">
var agent=navigator.userAgent.toLowerCase();
var is_iphone = ((agent.indexOf('iphone')!=-1));
if(is_iphone)
{
OAS_AD('MISC1'); } else {
OAS_AD('TOP');
}
</script>
</div>
</div>
I have done
WebSettings = this.page.getSettings(); //page is a WebView
s.setJavaScriptEnabled(); //enable JavaScript
I am fairly new to HTML/JS. Could someone please help?
Thanks!
EDIT: Adding code. Note: The section below and the the <div> section above appears in the <body> tag
<script language="JavaScript"><!--
//configuration
OAS_sitepage = 'www.boston.com/mobile/homepage';
var agent=navigator.userAgent.toLowerCase();var is_iphone = ((agent.indexOf('iphone')!=-1));if(is_iphone) {
OAS_listpos = 'MISC1,FOOTER,INTRO';
}else{
OAS_listpos = 'TOP,FOOTER,INTRO';
}
OAS_query='Unknown+Terminal';
OAS_url='http://rmedia.boston.com/RealMedia/ads/';OAS_target='_top';OAS_version=10;OAS_rn='001234567890';OAS_rns='1234567890';OAS_rn=new String(Math.random());OAS_rns=OAS_rn.substring(2, 11);
function OAS_NORMAL(pos){document.writeln('<A HREF="'+OAS_url+'click_nx.ads/'+OAS_sitepage+'/1'+OAS_rns+'#'+OAS_listpos+'!'+ pos+'?'+OAS_query+'" TARGET='+OAS_target+'>');document.writeln('<IMG SRC="'+OAS_url+'adstream_nx.ads/'+OAS_sitepage+'/1'+OAS_rns+'#'+OAS_listpos+'!'+pos+'?'+OAS_query+'" BORDER=0></A>');}
//--></script><script language="JavaScript1.1"><!--
OAS_version=11;if((navigator.userAgent.indexOf('Mozilla/3')!=-1)||navigator.userAgent.indexOf('Mozilla/4.0 WebTV')!=-1){OAS_version=10;}if(OAS_version >= 11)document.writeln('<SCR'+'IPT LANGUAGE=JavaScript1.1 SRC="'+OAS_url+'adstream_mjx.ads/'+OAS_sitepage+'/1'+OAS_rns+'#'+OAS_listpos+'?'+OAS_query+'"> <\/SCRIPT>');
//--></script><script language="JavaScript"><!--
document.writeln('');
function OAS_AD(pos){if(OAS_version >= 11)OAS_RICH(pos);else OAS_NORMAL(pos);}
//-->
</script>
EDIT2: I also tried ChromeWebClient - but turns out it only adds support for JS methods like alert(), prompt(),etc. There is not much documentation except this but the OP seems to have accepted an answer regardless of whether it worked for them. Nevertheless, that solution didn't work for me.
Please check these lines of code
var agent=navigator.userAgent.toLowerCase();
if(is_iphone)
{
OAS_AD('MISC1'); } else {
OAS_AD('TOP');
}
Obviously in your case the agent is not "iphone" so the code executed is
OAS_AD('TOP');
It would be useful if you attach that code too...
Jquery or JavaScript that displays content based on specifics date period
so we have like 3 dates
12/3/2010
12/11/2010
12/20/2010
and
Div Contents
Content 1 should be displaying from 12/3 to 12/11
Content 2 should be display from 12/11 to 12/20
and Content 3 should be displaying from 12/20 there after
First, like others said this whole thing is bad idea as you're depending on the client machine date/time and correct approach would be doing that in server side.
Anyway, guess you have your reasons so here is jQuery solution.
Have such HTML:
<div class="DateDiv"><span class="DateRange">1/1/2010 to 1/1/2011</span>I'll be visible during 2010</div>
<div class="DateDiv"><span class="DateRange">1/1/2011 to 1/1/2012</span>I'll be visible during 2011</div>
<div class="DateDiv"><span class="DateRange">1/1/2012 to 1/1/2013</span>I'll be visible during 2012</div>
Put the date range inside a span inside each div with the class "DateRange".
Next, have such CSS to have them initially hidden:
<style type="text/css">
.DateRange, .DateDiv { display: none; }
</style>
And finally, this script: (jQuery)
<script type="text/JavaScript">
$(function() {
$(".DateDiv").each(function(index) {
var sRange = $(this).find(".DateRange").html();
var arrTemp = sRange.split(" to ");
var dtFrom = new Date(arrTemp[0]);
var dtTo = new Date(arrTemp[1]);
var dtNow = new Date();
if (dtNow >= dtFrom && dtNow <= dtTo)
$(this).show();
});
});
</script>
Test case is available here feel free to mess around with it: http://jsfiddle.net/2BHLd/
I've created a simple code. It should work as you want (if I have understood you well).
I know, there's no doctype in my HTML and there are some missing tags. The HTML I've provided is just a kind of template.
<html>
<head>
<script type="text/javascript">
var date=new Date();
var year=date.getFullYear();
var month=date.getMonth();
var day=date.getDate(); // fixed
function SetDivContent() {
var div=document.getElementById('date_dependent');
if (year==2010 && month==11) { // fixed (the JavaScript months order is 0-11, not 1-12)
if (day>=3 && day<11) { // the following content will be displayed 12/03/2010, 12/04/2010, [...], 12/09/2010, 12/10/2010
div.innerHTML='content 1';
}
else if (day==11 || day==12) { // this one will be displayed 12/11/2010 and 12/12/2010
div.innerHTML='content 2';
}
else if (day>12) { // this one - 12/13/2010 and later, until the end of December
div.innerHTML='content 3';
}
}
else if (year==2011 && month>=0) div.innerHTML='content 3'; // OPTIONAL - just to ensure that content 3 is displayed even after December.
}
</script>
</head>
<body onload="SetDivContent()">
<div id="date_dependent"></div>
</body>
</html>
Please note that if you want to hide some data from users if the specified date hasn't come yet, you should better use something server-side for security reasons. Otherwise, any user may just read the page's source. Also remember that the following code is executed when the body is loaded, i.e. each time a user refreshes the page.
EDIT: Warning: there were two bad lines (I've made a mistake before). Anyway, I've fixed them. The current code works, I've tested it.