When using the Microsoft Translator, Is there a way to remove the widget, but retain translation? - javascript

I'm using the Microsoft Translation Widget, which I'd like to use to automatically translate a webpage without user interaction.
The problem is, I can't get rid of the widget that keeps popping up or hide it on document.ready because the CSS and JS get loaded from Microsoft's own script in the widget!
Does anyone know a way around this? I've looked everywhere and cannot find a solutuion for this.

Whoa, after some time playing around with that, I've finally achieved what you want.
It's kindda ugly, because of some needed workarounds, but it works, take a look at the fiddle.
The steps were:
Firstly, we must override the default addEventListener behavior:
var addEvent = EventTarget.prototype.addEventListener;
var events = [];
EventTarget.prototype.addEventListener = function(type, listener) {
addEvent.apply(this, [].slice.call(arguments));
events.push({
element: this,
type: type,
listener: listener
});
}
Then, we create a helper function removeEvents. It removes all the event listeners of an element.
var removeEvents = function(el, type) {
var elEvents = events.filter(function(ev) {
return ev.element === el && (type ? ev.type === type : true);
});
for (var i = 0; i < elEvents.length; i++) {
el.removeEventListener(elEvents[i].type, elEvents[i].listener);
}
}
When creating the script tag, in the way Microsoft says:
var s = d.createElement('script');
s.type = 'text/javascript';
s.charset = 'UTF-8';
s.src = ((location && location.href && location.href.indexOf('https') == 0) ? 'https://ssl.microsofttranslator.com' : 'http://www.microsofttranslator.com') + '/ajax/v3/WidgetV3.ashx?siteData=ueOIGRSKkd965FeEGM5JtQ**&ctf=True&ui=true&settings=Manual&from=';
var p = d.getElementsByTagName('head')[0] || d.dElement;
p.insertBefore(s, p.firstChild);
We must add a load event listener to that script, and the code below is fully commented:
s.addEventListener('load', function() {
// when someone changes the translation, the plugin calls the method TranslateArray
// then, we save the original method in a variable, and we override it
var translate = Microsoft.Translator.TranslateArray;
Microsoft.Translator.TranslateArray = function() {
// we call the original method
translate.apply(this, [].slice.call(arguments));
// since the translation is not immediately available
// and we don't have control when it will be
// I've created a helper function to wait for it
waitForTranslation(function() {
// as soon as it is available
// we get all the elements with an attribute lang
[].forEach.call(d.querySelectorAll('[lang]'), function(item, i) {
// and we remove all the mouseover event listeners of them
removeEvents(item, 'mouseover');
});
});
}
// this is the helper function which waits for the translation
function waitForTranslation(cb) {
// since we don't have control over the translation callback
// the workaround was to see if the Translating label is visible
// we keep calling the function, until it's hidden again
// and then we call our callback
var visible = d.getElementById('FloaterProgressBar').style.visibility;
if (visible === 'visible') {
setTimeout(function() {
waitForTranslation(cb);
}, 0);
return;
}
cb();
}
});
Update 1
After re-reading your question, it seems you want to hide all the widgets at all.
So, you must add the following code as soon as the translation is got:
waitForTranslation(function() {
document.getElementById('MicrosoftTranslatorWidget').style.display = 'none';
document.getElementById('WidgetLauncher').style.display = 'none';
document.getElementById('LauncherTranslatePhrase').style.display = 'none';
document.getElementById('TranslateSpan').style.display = 'none';
document.getElementById('LauncherLogo').style.display = 'none';
document.getElementById('WidgetFloaterPanels').style.display = 'none';
// rest of the code
});
I've created another fiddle for you, showing that new behavior.
Update 2
You can prevent the widget showing at all by adding the following CSS code:
#MicrosoftTranslatorWidget, #WidgetLauncher, #LauncherTranslatePhrase, #TranslateSpan, #LauncherLogo, #WidgetFloaterPanels {
opacity: 0!important;
}
And you can even prevent the before-translated text being showed, by hiding the document.body by default, and then showing it when the page is fully translated:
(function(w, d) {
document.body.style.display = 'none';
/* (...) */
s.addEventListener('load', function() {
var translate = Microsoft.Translator.TranslateArray;
Microsoft.Translator.TranslateArray = function() {
translate.apply(this, [].slice.call(arguments));
waitForTranslation(function() {
/* (...) */
document.body.style.display = 'block';
});
}
});
});
Take a look at the final fiddle I've created.

For me, this was the solution:
on your < style > section add this class
.LTRStyle { display: none !important }
Also, if you are invoking the translation widget this way:
Microsoft.Translator.Widget.Translate('en', lang, null, null, TranslationDone, null, 3000);
then add this to your callback (in this example is TranslationDone) function:
function TranslationDone() {
Microsoft.Translator.Widget.domTranslator.showHighlight = false;
Microsoft.Translator.Widget.domTranslator.showTooltips = false;
document.getElementById('WidgetFloaterPanels').style.display = 'none';
};

Related

Liferay/AlloyUI: Overriding util.js or disabling scrolling on form focus

How can I override (or hook) the function Liferay.Util.focusFormField in Liferay 7.0?
The method is defined in frontend-js-aui-web (portal-src\modules\apps\foundation\frontend-js\frontend-js-aui-web\src\main\resources\META-INF\resources\liferay\util.js).
The only way I could think of is to just overwrite it somewhere in a js-file, like so:
Liferay.Util.focusFormField = function(el) {
var doc = $(document);
var interacting = false;
el = Util.getDOM(el);
el = $(el);
doc.on(
'click.focusFormField',
function (event) {
interacting = true;
doc.off('click.focusFormField');
}
);
if (!interacting && Util.inBrowserView(el)) {
var form = el.closest('form');
var focusable = !el.is(':disabled') && !el.is(':hidden') && !el.parents(':disabled').length;
if (!form.length || focusable) {
el.focus(false); // modified
}
else {
var portletName = form.data('fm-namespace');
Liferay.once(
portletName + 'formReady',
function () {
el.focus(false); // modified
}
);
}
}
}
All I actually want is to disable the scrolling that happens whenever a form is submitted.
Does someone know what to do best to achieve this?
Another thing I found on the web is this: https://alloyui.com/api/files/alloy-ui_src_aui-form-validator_js_aui-form-validator.js.html#l216
But I cannot find it in liferay-7.0-source-files and no explanation how to override it.

Functions in Namespace Not Attaching Event Listeners to HTML Elements

I have a local page to help in HTML and JavaScript that helps me with some basic tasks at work. I've been going back over my code and rewriting it to use best practices, since it helps me learn, and recently I've been trying to study namespacing and put it to use by rewriting the common page functions and event listeners.
window.onload = (function() {
var automationPageWrapper = (function() {
var self = {}
self.evntListeners = {
btnTextChange: function() {
// Code that changes button text when clicked
},
btnColorChange: function(formID) {
// Code that iterates through buttons with a certain name
// and makes them all the same default color
}
}
self.listeners = {
btnListeners: function() {
// Add all event listeners having to do with buttons here
}
}
return self;
});
automationPageWrapper.listeners.btnListeners();
});
Why isn't this attaching the event listeners?
Is there a better way to be formatting/calling this?
Is this a professional method for setting up JavaScript code?
I tested the event listeners by taking the functions and posting them into the Chrome console, so I think they work.
The full text, since some people like reading through all of it:
// Global namespace for the Page Functions
window.addEventListener("onload", function() {
var automationPageWrapper = (function() {
var self = {};
// Namespace for event listeners
self.evtListeners = {
// Function to change the color of a selected button
btnColorChange: function(formName) {
var elementsByName = document.getElementsByName(formName);
for (var i = 0; i < elementsByName.length; i++) {
if (elementsByName[i].className == "active") {
elementsByName[i].className = "inactive";
break;
}
}
},
// Add the event listeners
listeners: {
btnListeners: (function () {
document.getElementById('sidebar').addEventListener("click", function(e){
self.evtListeners.btnColorChange('sidebuttons');
e.target.className = "active";
});
})()
}
}
return self;
})();
automationPageWrapper.listeners.btnColorChange();
});

Making bootstrap-tags responsive, jquery events lost

I am trying to change this demo:
http://maxwells.github.io/bootstrap-tags.html
into a responsive version in which I can set it to readOnly and remove it from readOnly as I like. This code:
var alltags = ["new tag", "testtag", "tets", "wawa", "wtf", "wtf2"];
$(document).ready(function() {
var tagbox = $('#my-tag-list').tags({
suggestions: alltags
});
var tagenable = true;
$('#my-tag-list').focusout(function() {
if (tagenable) {
tagbox.readOnly = true;
$('#my-tag-list').empty();
tagbox.init();
tagenable = false;
}
});
$('#my-tag-list').click(function() {
if(!tagenable) {
tagbox.readOnly = false;
$('#my-tag-list').empty();
tagbox.init();
tagenable = true;
}
});
});
seems to work fairly well, it makes everything readonly after focusout and editable when I click it. However, the editing does not work since I cannot insert new tags nor delete them (seems to be like event handling was lost or something like that).
I am guessing that emptying the #my-tag-list div is causing this, but I cannot yet find a way to use for instance "detach" instead that removes everything inside (not the element itself) and putting it back in again.
I tried to make a JS Fiddle, but it isn't really working so well yet:
http://jsfiddle.net/tomzooi/cLxz0L06/
The thing that does work is a save of the entire website, which is here:
https://www.dropbox.com/sh/ldbfqjol3pppu2k/AABhuJA4A6j9XTxUKBEzoH6za?dl=0
this link has the unminimized JS of the bootstrap-tags stuff I am using:
https://github.com/maxwells/bootstrap-tags/blob/master/dist/js/bootstrap-tags.js
So far I managed to do this with some modifications of the bootstrap javascript code. I use two different tagbox which I hide and unhide with some click events.
var tagbox = $('#my-tag-list').tags({
suggestions: alltags,
tagData: tmp_tags,
afterAddingTag: function(tag) { tagboxro.addTag(tag); },
afterDeletingTag: function(tag) {tagboxro.removeTag(tag); }
});
var tagboxro = $('#my-tag-listro').tags({
suggestions: alltags,
tagData: tmp_tags,
readOnly: 'true',
tagSize: 'sm',
tagClass: 'btn-info pull-right'
});
$(document).mouseup(function (e) {
var container = $("#my-tag-list");
if (!container.is(e.target) // if the target of the click isn't the container...
&& container.has(e.target).length === 0) { // ... nor a descendant of the container
if (tagsave) {
$("#my-tag-listro").show();
$("#my-tag-list").hide();
var tags = tagbox.getTags();
$.post("%basedir%/save.php", {
editorID:"new_tags",
tags:tags
}, function(data,status){
//alert("Data: " + data + "\nStatus: " + status);
});
tagsave = false;
}
}
});
$('#my-tag-listro').click(function() {
tagsave = true;
//$(".tag-list").toggle();
$("#my-tag-list").show();
$("#my-tag-listro").hide();
});
I had to modify the code of bootstrap-tags.js to allow for this since it normally deletes all of the usefull functions when it is considered readonly in the init function:
if (this.readOnly) {
this.renderReadOnly();
this.removeTag = function(tag) {
if (_this.tagsArray.indexOf(tag) > -1) {
_this.tagsArray.splice(_this.tagsArray.indexOf(tag), 1);
_this.renderReadOnly();
}
return _this;
};
this.removeTagClicked = function() {};
this.removeLastTag = function() {};
this.addTag = function(tag) {
_this.tagsArray.push(tag);
_this.renderReadOnly();
return _this;
};
this.addTagWithContent = function() {};
this.renameTag = function() {};
return this.setPopover = function() {};
}
would be awesome if this feature was incorporated in a somewhat less hacky way though :)

How to achieve a queue of object instances of jQuery modals, assuring only one instance is on per time?

I've a task of building a modal prompt, that's been simple so far describing its methods like "show", "hide" when it comes down just to DOM manupulation.
Now comes the hardship for me... Imagine we have a page on which there are several immediate calls to construct and show several modals on one page
//on page load:
$("browser-deprecated-modal").modal();
$("change-your-city-modal").modal();
$("promotion-modal").modal();
By default my Modal (and other libraries i tried) construct all of these modals at once and show them overlapping each other in reverse order -
i.e $(promotion-modal) is on the top, while the
$("browser-deprecated-modal") will be below all of them. that's not what i want, let alone overlapping overlays.
I need each modal to show up only when the previous one (if there'are any) has been closed. So, first we should see "browser-deprecated-modal" (no other modals underneath), upon closing it there must pop up the second one and so on.
I've been trying to work it out with this:
$.fn.modal = function(options) {
return this.each(function() {
if (Modal.running) {
Modal.toInstantiateLater.push({this,options});
} else {
var md = new Modal(this, options);
}
});
}
destroy :function () {
....
if (Modal.toInstantiateLater.length)
new Modal (Modal.toInstantiateLater[0][0],Modal.toInstantiateLater[0][1]);
}
keeping a track of all calls to construct a Modal in a array and in the "destroy" method make a check of this array is not empty.
but it seems awkward and buggy me thinks.
i need a robust and clear solution. I've been thinking about $.Callbacks or $.Deferred,
kinda set up a Callback queue
if (Modal.running) { //if one Modal is already running
var cb = $.Callbacks();
cb.add(function(){
new Modal(this, options);
});
} else { //the road is clear
var md = new Modal(this, options);
}
and to trigger firing cb in the destroy method, but i'm new to this stuff and stuck and cannot progress, whether it's right or not, or other approach is more suitable.
Besides, I read that callbacks fire all the functions at once (if we had more than one extra modal in a queue), which is not right, because I need to fire Modal creation one by one and clear the Callback queue one by one.
Please help me in this mess.
My code jsfiddle
I got rid of the counter variable, as you can use toInstantiateLater to keep track of where you are, and only had to make a few changes. Give this a try...
Javscript
function Modal(el, opts){
this.el = $(el);
this.opts = opts;
this.overlay = $("<div class='overlay' id='overlay"+Modal.counter+"'></div>");
this.wrap = $("<div class='wrap' id='wrap"+Modal.counter+"'></div>");
this.replace = $("<div class='replace' id='replace"+Modal.counter+"'></div>");
this.close = $("<span class='close' id='close"+Modal.counter+"'></span>")
if (Modal.running) {
Modal.toInstantiateLater.push(this);
}
else {
Modal.running = true;
this.show();
}
}
Modal.destroyAll = function() {
Modal.prototype.destroyAll();
};
Modal.prototype = {
show: function() {
var s = this;
s.wrap.append(s.close);
s.el.before(s.replace).appendTo(s.wrap).show();
$('body').append(s.overlay).append(s.wrap);
s.bindEvents();
Modal.currentModal = s;
},
bindEvents: function() {
var s = this;
s.close.on("click.modal",function(e){
s.destroy.call(s,e);
});
},
destroy: function(e) {
var s = this;
s.replace.replaceWith(s.el.hide());
s.wrap.remove();
s.overlay.remove();
if (Modal.toInstantiateLater.length > 0) {
Modal.toInstantiateLater.shift().show();
}
else {
Modal.running = false;
}
},
destroyAll: function(e) {
Modal.toInstantiateLater = [];
Modal.currentModal.destroy();
}
}
Modal.running = false;
Modal.toInstantiateLater = [];
Modal.currentModal = {};
$.fn.modal = function(options) {
return this.each(function() {
var md = new Modal(this, options);
});
}
$("document").ready(function(){
$("#browser-deprecated-modal").modal();
$("#change-your-city-modal").modal();
$("#promotion-modal").modal();
$("#destroy-all").on("click", function() {
Modal.destroyAll();
});
});
jsfiddle example
http://jsfiddle.net/zz9ccbLn/4/

ckeditor - onshow overiding custom definition

when using the ckeditor link dialog, I have custom code for some extra options. I would also like to grab the selected text to use - so I have called:
selectedContents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
I want this to happen when the dialog is loaded. So I wrote an "onShow()" handler function... but that messes up the customizations that I have made to the dialog. I'm guessing that my onShow is grabbing the normal process for that event - how can I continue with the normal processing at that point?
dialogDefinition.onShow = function(evt)
{
contents = CKEDITOR.instances['my_editor'].getSelection().getSelectedText();
// now here, continue as you were...
}
Ok, I still have some issues, but the answer to this question is to grab the existing "onShow" handler before overwriting it. Use a global, then it can be called within the new handler:
var dialogDefinition = ev.data.definition;
var oldOnShow = dialogDefinition.onShow;
dialogDefinition.onShow = function(evt) {
// do some stuff
// do some more stuff
// call old function
oldOnShow();
}
Depending on Andy Wallace code:
var oldOnShow = dialogDefinition.onShow;
var newOnShow = function () {
//your code
}
and then:
dialogDefinition.onShow = function(){
oldOnShow.call(this, arguments);
newOnShow.call(this, arguments);
}
It helps me!
Correct syntax is:
/* if new picture, then open the Upload tab */
CKEDITOR.on('dialogDefinition', function(ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
var dialog = dialogDefinition.dialog;
if (dialogName == 'image2') {
dialogDefinition.onShow = CKEDITOR.tools.override(dialogDefinition.onShow, function(original) {
return function() {
original.call(this);
CKEDITOR.tools.setTimeout( function() {
if (dialog.getContentElement('info', 'src').getValue() == '') {
dialog.selectPage('Upload');
}
}, 0);
}
});
}
});

Categories