I am using the i18next script in my jQuery Mobile page in Cordova/PhoneGap app.
I have the below scripts included in the bottom of HTML page.
<script src="js/jquery-1.8.3.min.js"></script>
<script src="js/jquery.mobile-1.3.2.min.js"></script>
<script src="js/i18next-1.7.1.min.js"></script>
<script src="js/main.js"></script>
The main.js file has some logic which will be included in all pages of my app.
main.js File:
function doBootstrap() {
i18n.init({lng: "en", fallbackLng: 'en'});
var header = "some tags";
header += '<h1>' + i18n.t("app.title") + '</h1>';
// other functions
}
I will be using the script to get the translated values across the page in different sections
The above function is called in Cordova devideready function which is placed beow the above mentioned includes. .
document.addEventListener("deviceready", onDeviceReady, true);
function onDeviceReady() {
doBootstrap();
}
With all the above setup I get the below error in i18next-1.7.1.min.js file.
Uncaught TypeError: Cannot read property 'defaultValue' of undefined
The .json file is present in \locales\en\translation.json and the content of it is below. No error or warning is displayed in console.
{
"app": {
"title": "Title"
}
}
What I am missing with the plugin setup?
Finally, I have made it to work. It was a bug in the code and the developer fixed it within minutes of reporting it. Great job..
Here is the link for the issue.
https://github.com/jamuhl/i18next/issues/166
Also as per the developer of plugin, I did the following changes.
function doBootstrap() {
var opts = {
getAsync: true, lng: "en", fallbackLng: 'en'
};
i18n.init(opts).done(doBootstrapMain);
}
function doBootstrapMain() {
// my regular functions
}
Related
I take the html code of the page with the plugin and send it with the form.
I need to change the 'content_security_policy' part to be able to switch to v3. But it doesn't work somehow, I get jquery error every time.
chrome.tabs.executeScript(null, {
file: "source.js"
}, function() {
In this part
chrome.scripting.executeScript(null, {
file: "source.js"
}, function() {
I changed to.
I really want to share constants with all my js files, background_serviceworker.js and popup.js.
const EXTENSION_MODE = {
SEARCH_ONLY: "searchOnly",
FILTER: "filter",
OFF: "off"
}
Just putting vars in the background_serviceworker.js and using getBackgroundPage() seems a bit messy to me (can make the background file very big).
I created constants.js.
// constants.js
var EXTENSION_MODE = Object.freeze({
SEARCH_ONLY: "searchOnly",
FILTER: "filter",
OFF: "off"
})
Inject it to the background-service-worker file (using an answer from here Service worker registration failed. Chrome extension to actually see the errors from the injected script. Without, you only see very general error)
// background.js
try { importScripts("constants.js"); } catch (e) { console.error(e); }
Now popup.js still don't have access to that, because it runs in isolated contexed.
So I Also injected it to the popup.html (In the good old fashion way).
<!-- popup.html -->
<body>
<some-other-elements/>
<script src="./constants.js"></script>
<script src="./popup.js"></script>
</body>
And I can use it in popup.js
// popup.js
console.log("popup: " + EXTENSION_MODE.FILTER);
PS. on content scripts (injected using the chrome.scripting.executeScript), we won't use it. There we need to start using Storage and Messaging https://developer.chrome.com/docs/extensions/reference/storage/
https://developer.chrome.com/docs/extensions/mv3/messaging/
So I know you can get the userscript's version info and use it as a variable in the userscript like so...
// #version 1.2.1
// #grant GM_info
var version = GM_info.script.version;
console.log(`${version}`); // 1.2.1
I thought I could be able to use that variable on a different webpage. In this case, I want to display whatever the latest version is on the installation instructions page so that it says something to the effect of "Script name v.1.2.1"
I have a tag on my page (install.html) like this
<td>Script Name v.<span id="version"></span></td>
I have the userscript linked using a script tag on the install.html page (this may be the reason this isn't working):
<script src="Scripts/scriptName.user.js"></script>
with a line of code
document.getElementById("version").innerText=`${version}`;
What am I doing wrong, or is this even possible.
Note: I want this to work even if the person doesn't have the userscript installed yet.
Yes, you can show userscript data on a webpage provided that either the webpage, or your hosting server, can see and GET the script (possibly cross-domain).
But <script src="Scripts/scriptName.user.js"> won't work, because:
It reads in and runs the script as vanilla javascript. There's no way for you to read the source code or the comments where the script's metadata lurks.
Many script hosts, like GitHub, won't serve the file to a <script> tag at all (CORS blocked). Or, some do, but send the wrong mime type.
Tampermonkey can't fire for <script> nodes, and it would be a major security disaster if it could.
So obviously, GM_info will not be available.
In fact, if the script uses any Tampermonkey native functions it will crash even if it loads. Note that this doesn't mean the metadata. That's harmless by itself.
Ditto if #require or #resource assets are needed. (And not independently loaded by the page.)
You must read in the userscript as text, and then parse the string for the version info.
For example, for this userscript:
// ==UserScript==
// #name StackExchange, Add kbd, sup, and sub shortcuts
...
// #version 4.2
...
The following code will get the version:
$.get ("https://cdn.jsdelivr.net/gh/BrockA/SE-misc/Add_kbd_sup_sub_shortcuts.user.js", scrptTxt => {
var versionMtch = scrptTxt.match (/\/\/\s+#version\s+([0-9.]+)/i);
if (versionMtch && versionMtch.length > 1) {
console.log ("The script is version: ", versionMtch[1]);
}
else {
console.log ("Version metadata not found.");
}
} );
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
Or HTML you can put at the end of your web page:
<script src="http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script>
$(document).ready ( () => {
$.get ("https://cdn.jsdelivr.net/gh/BrockA/SE-misc/Add_kbd_sup_sub_shortcuts.user.js"
, scrptTxt => {
var versionMtch = scrptTxt.match (/\/\/\s+#version\s+([0-9.]+)/i);
if (versionMtch && versionMtch.length > 1) {
console.log ("The script is version: ", versionMtch[1]);
}
else {
console.log ("Version metadata not found.");
}
} );
} );
</script>
</body></html>
I need to use Twitter's Search API. I read twitter's developer documentation and it says that client side authentication is not recommended anymore. But, since mine is really a small application and on a very tight deadline, I decided to use codebird-js.
Here is my code:
<script type="text/javascript" src="sha1.js"></script>
<script type="text/javascript" src="codebird.js"></script>
<script type="text/javascript">
function loginTwitter() {
var cb = new Codebird();
cb.setConsumerKey("my_consumer_key","my_consumer_secret");
cb.setToken("my_token", "my_token_secret");
cb.__call(
"search_tweets",
"q=Twitter",
function (reply) {
alert("hey");
},
true
);
}
</script>
Dont think there is any problem with the callback of search tweets, since this is what is documented in codebird-js.Kindly suggest any alternatives to make the code work.
Also, I enabled the option "Allow application to sign in with twitter" in application settings.
You have to make some syntax corrections to your code and to call the "loginTwitter()" function; the code should be:
<script type="text/javascript" src="sha1.js"></script>
<script type="text/javascript" src="codebird.js"></script>
<script type="text/javascript">
function loginTwitter() {
var cb = new Codebird();
cb.setConsumerKey("my_consumer_key", "my_consumer_secret");
cb.setToken("my_token", "my_token_secret");
cb.__call(
"search_tweets",
"q=Twitter",
function (reply) {
alert(JSON.stringify(reply)); //do something with the result
},
true
);
};
loginTwitter();
</script>
And don't forget to download the codebird for javascript and put its files into the same folder as your main file (according to the path that you have put in your script).
I am writing a chrome extension which will enable transliteration for specific textboxes in facebook.
I have used the script tab to load https://www.google.com/jsapi in background.html
here is the code i have used in a content script
i tried to load using ajax and the generic way.
when i checked it said google undefined.
/*
$.ajax({
url: "https://www.google.com/jsapi",
dataType: "script",
});
*/
var script = document.createElement("script");
script.setAttribute('type','text/javascript');
script.setAttribute('src','https://www.google.com/jsapi?'+(new Date()).getTime());
document.body.appendChild(script);
$(document).ready(function()
{
alert(google)
if(window.location.href.indexOf('facebook.com'))
yes_it_is_facebook();
})
function yes_it_is_facebook()
{
// document.getElementsByName('xhpc_message_text')[0].id = 'facebook_tamil_writer_textarea';
// alert(document.getElementsByName('xhpc_message').length)
google.load("elements", "1", { packages: "transliteration" });
google.setOnLoadCallback(onLoad);
}
function onLoad()
{
var options = {
sourceLanguage:
google.elements.transliteration.LanguageCode.ENGLISH,
destinationLanguage:
[google.elements.transliteration.LanguageCode.HINDI],
shortcutKey: 'ctrl+g',
transliterationEnabled: true
};
var control = new google.elements.transliteration.TransliterationControl(options);
control.makeTransliteratable(['facebook_tamil_writer_textarea']);
}
and i have https://www.google.com/jsapi in manifest.json content script array.
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/jquery-1.7.2.min.js", "js/myscript.js", "https://www.google.com/jsapi"]
}
],
it showed an error
Could not load javascript https://www.google.com/jsapi for content
script
here is my manifest.json
{
"name": "Facebook Tamil Writer",
"version": "1.0",
"description": "Facebook Tamil Writer",
"browser_action": {
"default_icon": "images/stick-man1.gif",
"popup":"popup.html"
},
"background_page": "background.html",
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["js/jquery-1.7.2.min.js", "js/myscript.js", "https://www.google.com/jsapi"]
}
],
"permissions": [
"http://*/*",
"https://*/*",
"contextMenus",
"tabs"
]
}
in that i have added https://www.google.com/jsapi for your understanding and i have tested removing that also.
so how do i load that javascript into a document context . that is when ever a web page is loaded... here i specifically loading for facebook. still i have to correct the indexof condition because it is not giving the proper result but that is not the problem to this context of my question.
so please suggest me.
I don't seem to find any documentation regarding this but I think you cannot mention an http:// path in content_scripts option. A possible work around could be this:
$('head').append("<script type='text/javascript' src='http://google.com/jsapi'>");
Or loading it via ajax request as you have commented out in your code.
Secondly google.com/jsapi will have to be loaded before you can use it in your script. In your manifest you are loading your script first and then google.com/jsapi.
A friendly advice:
jQuery by default disallows caching by appending timestamp at the end of url. Since the script you are trying to load is not likely to change in short durations you can pass cache: false as an option for saving load time. Check out this page for more info.
Better yet you can bundle the script with your package so that there is no ajax request associated with your extension, that will add to the speed of your extension.
One of the biggest issues with google.load is that it cannot properly load resources after the page has fully loaded, because the API uses document.write to inject scripts/styles. To fix the issue, two methods have to be patched:
(function(g) {
var loader_d = g.loader.d,
setOnLoadCallback = g.setOnLoadCallback;
// Force not to use document.write when the document is loaded
g.loader.d = g.loader.writeLoadTag = function(a, b) {
loader_d(a, b, document.readyState === 'complete');
};
// Executes functions directly when page has loaded
g.setOnLoadCallback = function(a_listener, b) {
if (b || document.readyState !== 'complete') {
setOnLoadCallback(a_listener, b);
} else {
// When the API is not loaded yet, a TypeError with google.
// will be thrown. Not a ReferenceError, because google.* is defined
// Retry max *c* times.
var c = 5;
b = function() {
try {
a_listener();
} catch (e) {
if (e instanceof TypeError && (''+e).indexOf('google.')!=-1) {
if (c--) setTimeout(b, 2000);
}
}
};
b();
}
};
})(google);
Now, problem 2: Content Scripts run in an isolated environment: any properties of the global namespace, window, are not accessible. So, any injected APIs are not visible to your Content Script.
To fix this, see the following Stack Overflow answer: Building a Chrome Extension.
This might help with understanding Chrome's security policies
CSP
In there is says that if you attach a script tag to the page (not the popup or content script) it loads in the context of the page not your extension. And script from the extension can not talk to scripts of the page. If you look at the page script's you'll see it there but not under your extension scripts.
I discovered this while trying to inject the Google API script.
script = document.createElement('script');
script.src = "https://apis.google.com/js/client.js?onload=init";
(document.head||document.documentElement).appendChild(script);
The init function is defined in my content script. But the Goolge API script is loaded as a page script. So if I do this
var script = document.createElement('script');
script.innerText = "function init(){ alert('hi'); }";
(document.head||document.documentElement).appendChild(script);
script = document.createElement('script');
script.src = "https://apis.google.com/js/client.js?onload=init";
(document.head||document.documentElement).appendChild(script);
The injected init function is called and I see the alert 'hi'. Not sure if this helps but I figured I'd make a note of it for anyone else struggling with loading the Google apis. I'll update this answer if I figure out a way to actually get it loaded.