How can a (Firefox) WebExtension know its own version? - firefox-addon-webextensions

I'm porting a legacy Firefox extension to WebExtensions. I want to know at run time the version number of the extension itself. Right now I'm doing:
let extensionVersion = (function() {
var xhr = new XMLHttpRequest();
xhr.overrideMimeType('application/json');
xhr.open('GET', browser.extension.getURL('manifest.json'), false);
xhr.send(null);
var manifest = JSON.parse(xhr.responseText);
return manifest.version;
})();
This dirty hack which relies on synchronous XHR. Is there a better way?

There is a dedicated function for retrieving the manifest:
browser.runtime.getManifest().version
https://developer.mozilla.org/en-US/Add-ons/WebExtensions/API/runtime/getManifest

Related

AngularJS GET receives empty reply in Chrome but not in Fiddler

I'm implementing file download using AngularJS and WCF. My back-end is a .NET project hosted in IIS. The file is serialized as an array of bytes and then on the client side I utilize the File API to save the content.
To simplify the problem, back-end is like:
[WebInvoke(Method = "GET", UriTemplate = "FileService?path={path}")]
[OperationContract]
public byte[] DownloadFileBaseOnPath(string path)
{
using (var memoryStream = new MemoryStream())
{
var fileStream = File.OpenRead(path);
fileStream.CopyTo(memoryStream);
fileStream.Close();
WebOperationContext.Current.OutgoingResponse.Headers["Content-Disposition"] = "attachment; filename=\"Whatever\"";
WebOperationContext.Current.OutgoingResponse.ContentType = "application/octet-stream"; // treat all files as binary file
return memoryStream.ToArray();
}
}
And on client side, it just sends a GET request to get those bytes, converts in into a blob and save it.
function sendGetReq(url, config) {
return $http.get(url, config).then(function(response) {
return response.data;
});
}
Save the file then:
function SaveFile(url) {
var downloadRequest = sendGetReq(url);
downloadRequest.then(function(data){
var aLink = document.createElement('a');
var byteArray = new Uint8Array(data);
var blob = new Blob([byteArray], { type: 'application/octet-stream'});
var downloadUrl = URL.createObjectURL(blob);
aLink.setAttribute('href', downloadUrl);
aLink.setAttribute('download', fileNameDoesNotMatter);
if (document.createEvent) {
var event = document.createEvent('MouseEvents');
event.initEvent('click', false, false);
aLink.dispatchEvent(event);
}
else {
aLink.click();
}
setTimeout(function () {
URL.revokeObjectURL(downloadUrl);
}, 1000); // cleanup
});
}
This approach works fine with small files. I could successfully download files up to 64MB. But when I try to download a file larger than 64MB, the response.body is empty in Chrome. I also used Fiddler to capture the traffic. According to Fiddler, Back-end has successfully serialized the byte array and returned it. Please refer to the screenshot below.
In this example, I was trying to download a 70MB file:
And the response.data is empty:
Any idea why this is empty for file over 70MB? Though the response itself is more than 200MB, I do have enough memory for that.
Regarding to the WCF back-end, I know I should use Stream Mode when it comes to large files. But the typical use of my application is to download files less than 10MB. So I hope to figure this out first.
Thanks
Answer my own question.
Honestly I don't know what's going wrong. The issue still persists if I transfer it as a byte array. I eventually gave up this approach by returning a stream instead. Then on the client side, adding the following configuration
{responseType : blob}
and save it as a blob.

Angular translate - When multiple loader it execute only the last one

I've got a project using angular translate with a custom loader.
Basically, this is the config in my provider (which is working perfectly).
Provider (stuff executed in the config of my app)
$translateProvider.useSanitizeValueStrategy('sanitize');
$translateProvider.useLoader('componentsTranslationLoader');
$translateProvider.preferredLanguage($language);
As you can see, I use my own componentsTranslationLoader. It does the stuff as expected.
Factory (componentsTranslationLoader)
return function(options) {
var deferred = $q.defer();
var translations = {};
$http.get('languages/components/' + options.key + '.json').success(function(keys) {
translations = keys;
deferred.resolve(translations);
});
return deferred.promise;
};
Everythings is fine from here.
I have to use a library in this project (company's one, I can edit it), and this library also has his own angular translate stuff (basically the same thing).
It has a custom loader, initialized into the config.
When my project is executed, I expect that both loader do their stuff and extend the language with their keys.
It didn't.
Only the last loader is executed (see it with logs).
So, how can I resolve this conflict properly please ?
Is there something wrong with my way of using angular translate ?
Thanks for the help guys.
Edit (more informations added)
I added more call like this one into the config with different 'fake' loader:
$translateProvider.useLoader('aFakeLoaderWithLogs');
And the problem still the same, only the last one into the config is called.
I searched for topics with similar issues and found nothing, even in the documentation.
Try this approach of merging responses. Works for me very well.
function customLoader($http, $q, localeUrl, errorCodeUrl) {
return function (options) {
var deferred = $q.defer();
var translations = [];
$q.all([
$http.get(localeUrl + "locale-" + options.key +".json"),
$http.get(errorCodeUrl + "?lang=cs")
]).then(function(response, status) {
translations.push(response[0].data);
translations.push(response[1].data);
console.log(translations);
deferred.resolve(translations);
return translations;
});
return deferred.promise;
};
}

Why downloading tiff doesn't work in Firefox?

In my project i use AngularJS so a directive for downloading files was created. It contains the following:
scope.$on('downloaded', function(event, data) {
var hiddenLink = document.createElement('a');
$(hiddenLink).attr({
href: 'data:application/tiff;base64,' + data.Attachment,
download: data.AttachmentFileName
});
if (isIEorFirefox) {
$(hiddenLink).click(function(event){
event.preventDefault();
var byteString = atob(data.Attachment);
var buffer = new ArrayBuffer(byteString.length);
var intArray = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
var blob = new Blob([buffer],{type:'image/tiff'});
window.navigator.msSaveOrOpenBlob(blob, data.AttachmentFileName);
});
$(hiddenLink).trigger('click');
} else {
hiddenLink.click();
}
});
Previously there was an issue - download in IE simply didn't start - but for now as you can it has been eliminated. Though another issue remains - currently this code doesn't start download in Firefox. There is only one question - why?
UPDATE:
I've updated initial code because it didn't save file properly in IE. Now it does. Searching over the web i still cannot find a way to make file download in FF. Moreover FF still seems not to have any native way to save files according to this article https://hacks.mozilla.org/2012/07/why-no-filesystem-api-in-firefox/. I would be grateful if someone prove me wrong.
hiddenLink.click();
should perhaps be:
$(hiddenLink).click();
or same as other:
$(hiddenLink).trigger('click');
Assume you also need the event handler added as well...

Mean.io framework with socket.io

How to use socket.io in Mean.io stack?
First of all, Mean.io changes their folder structure very regularly.. So my question is where is the best place to configure socket.io ? or is it better to use express.io ?
Second I am still not quite sure where to look for to find code that tells mean.io to listen for port, I have found a port is defined in config folder in all.js file, but real problem is as soon as I define server.listen(port) app doesn't load. and if I don't app loads but socket.io doesn't work.
Also I have another question about /socket.io/socket-io.js file? I have copied that in index folder, but my app can't find it or says 404 error. I know it's not an actual file sitting on any such location as far as I have understood, also people suggested to put that line as 127.0.0.1/socket.io/socket-io.js but none made the js file available for the app to be able to run socket.io.
What is the proper way of defining socket.io in mean.io framework?
I also faced the same issue and took me about a week to finally get it right. I'll try to explain what I did:
app.js
In this file, I just invoke the code that creates and sets up a socket.io object for me, which is then passed to the routes module.
'use strict';
/*
* Defining the Package
*/
var Module = require('meanio').Module;
var MeanSocket = new Module('chat');
/*
* All MEAN packages require registration
* Dependency injection is used to define required modules
*/
MeanSocket.register(function(app, http) {
var io = require('./server/config/socketio')(http);
//We enable routing. By default the Package Object is passed to the routes
MeanSocket.routes(io);
return MeanSocket;
});
server/config/socketio.js
This file simply configures the socket.io object. Please note that I had to upgrade meanio module to version 0.5.26 for this work, as http object (express server) is not available in older meanio versions. Moreover, in case you want to use ssl, you can inject https instead of http.
'use strict';
var config = require('meanio').loadConfig(),
cookie = require('cookie'),
cookieParser = require('cookie-parser'),
socketio = require('socket.io');
module.exports = function(http) {
var io = socketio.listen(http);
io.use(function(socket, next) {
var data = socket.request;
if (!data.headers.cookie) {
return next(new Error('No cookie transmitted.'));
}
var parsedCookie = cookie.parse(data.headers.cookie);
var sessionID = parsedCookie[config.sessionName];
var parsedSessionID = cookieParser.signedCookie(parsedCookie[config.sessionName], config.sessionSecret);
if (sessionID === parsedSessionID) {
return next(new Error('Cookie is invalid.'));
}
next();
});
return io;
};
routes/chat.js
Finally, use the routes file to define the socket events, etc.
'use strict';
// The Package is passed automatically as first parameter
module.exports = function(MeanSocket, io) {
io.on('connection', function(socket) {
console.log('Client Connected');
socket.on('authenticate', function(data, callback) {
});
});
};
Hope this helps!
The simplest way would be to install the socket package...
mean install socket

WebClient issue

I am trying to get contents of http://www.yahoo.com using WebClient#DownloadStringAsync(). However as Silverlight doesn't allow cross domain calls i am getting TargetInvocationException. I know we have to put clientaccesspolicy.xml and crossdomain.xml in our web server root but that is possible only if i have control on my services. Currently Google is not under my control ;), so how do i handle it?
I've did a workaround by making a WCF service in my web application and then calling WebClient. This works perfectly but it is rather ineffecient. Is there any other better way than this?
Thanks in advance :)
Silverlight's cross domain restricitions cause many developers to implement workarounds. If you need to display the html page you get back you should look into Silverlight 4 (WebBrowser) control although this only seems to work when running out-of-browser mode.
If you need to parse through the content you can try some of the following:
For a managed code solution the proxy service you have already implemented is your best option.
Write a Java applet that returns this information. Silverlight can interopt to javascript which can interopt into Java applets. This also works in the reverse but a little difficult to setup. (If you need more info on this let me know).
Use javascript XmlHttpRequest to get the data you want from the source. This can be difficult when supporting multiple browsers. This link shows an example of how to do this (you will need to scroll down). Javascript get Html
Code:
var xmlHttpRequestHandler = new Object();
var requestObject;
xmlHttpRequestHandler.createXmlHttpRequest = function(){
var XmlHttpRequestObject;
if(typeof XMLHttpRequest != "undefined")
{
XmlHttpRequestObject = new XMLHttpRequest();
}
else if(window.ActiveXObject)
{
var tryPossibleVersions =["MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp","Microsoft.XMLHttp"];
for(i=0;i<tryPossibleVersions.length;i++)
{
try
{
XmlHttpRequestObject = new ActiveXObject(tryPossibleVersions[i]);
break;
}
catch(xmlHttpRequestObjectError)
{
// Ignore Exception
}
}
}
return XmlHttpRequestObject;}
function getHtml(){
var url = document.getElementById('url').value;
if(url.length > 0)
{
requestObject = xmlHttpRequestHandler.createXmlHttpRequest();
requestObject.onreadystatechange=onReadyStateChangeResponse;
requestObject.open("Get",url, true);
requestObject.send(null);
}}
function onReadyStateChangeResponse(){
var ready, status;
try
{
ready = requestObject.readyState;
status = requestObject.status;
}
catch(e) {}
if(ready == 4 && status == 200)
{
alert(requestObject.responseText);
}}

Resources