Introduction
I work with RapidWeaver — Mac OS X CMS application — and it uses no server environment. It has an editor and a preview mode. The preview mode is a Webkit based renderer, and I can use 'Inspect Element', like you normally could do in Safari.
I want to store some settings for a toolbar, either using localStorage or SQLite. I have read some information about indexedDB, though I have found no concrete implementations on how to use it.
Problems with localStorage
localStorage works fine when I stay in the preview mode, when I switch between editor and preview mode the url — location.href — is slightly altered:
file:///private/var/folders/s7/x8y2s0sd27z6kdt2jjdw7c_c0000gn/T/TemporaryItems/RapidWeaver/98970/document-143873968-28/RWDocumentPagePreview/code/styled/index.html
file:///private/var/folders/s7/x8y2s0sd27z6kdt2jjdw7c_c0000gn/T/TemporaryItems/RapidWeaver/98970/document-143873968-29/RWDocumentPagePreview/code/styled/index.html
document-143873968-28 changes into
document-143873968-29
What I have read about localStorage, that it's basically globalStorage[location.hostname] for FireFox. As far as I know globalStorage is not supported in Safari, so I can't try that.
Problems with SQLite
When I try to open a database:
var shortName = 'mydatabase';
var version = '1.0';
var displayName = 'My Important Database';
var maxSize = 65536; // in bytes
var db = openDatabase(shortName, version, displayName, maxSize);
I get this in my console:
SECURITY_ERR: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
That basically wraps up my question, I will appreciate any answers or comments sincerely.
Using the following solution: Implementing a WebView database quota delegate with a few modifications I was able to get it to work.
The following delegate method worked for me (place in your webViewDelegate):
- (void)webView:(WebView *)sender frame:(WebFrame *)frame exceededDatabaseQuotaForSecurityOrigin:(id) origin database:(NSString *)databaseIdentifier
{
static const unsigned long long defaultQuota = 5 * 1024 * 1024;
if ([origin respondsToSelector: #selector(setQuota:)]) {
[origin performSelector:#selector(setQuota:) withObject:[NSNumber numberWithLongLong: defaultQuota]];
} else {
NSLog(#"could not increase quota for %#", defaultQuota);
}
}
By default the database is given 0 bytes, which results in the vague error message you get above. The above method is called after an attempt is made to create a database when there is not enough space. Note that this method is defined in WebUIDelegatePrivate.h ( http://opensource.apple.com/source/WebKit/WebKit-7533.16/mac/WebView/WebUIDelegatePrivate.h ) and using may preclude you from submitting your app to the mac app store.
localStorage is a html5 mechanism to give scripts a bit more space than cookies. Safari supports it: https://developer.apple.com/library/archive/documentation/iPhone/Conceptual/SafariJSDatabaseGuide/Name-ValueStorage/Name-ValueStorage.html
I don't know offhand what, if any, path restrictions it should have for file:/// based apps.
Edit: looking into the path restrictions further, I see that what you got should work with Safari, FF recently fixed a bug that would keep it from working there: https://bugzilla.mozilla.org/show%5Fbug.cgi?id=507361
Related
I am developing a Mozilla Firefox extension using the Add-on SDK. On every tab change event, I want to read cookies of specified host which is open in another tab. I reached up to tab change, but am trying to figure out the way to get the cookies of specified host in recent activated tab.
var tabs = require("sdk/tabs");
tabs.on('activate', function(tab) {
// want to get cookies here.
});
Well, from within a tabs.on('activate') event handler, you have the tab. The tab object has a property url from which you can obtain the host. Once you have the host, you can get the cookies for that host. You have not stated what you want to do with them. So, here is just a way to enumerate them.
In order to use some methods of Services.cookies (nsICookieManager2) you will also need to require Chrome Authority.
var domainToUse = 'google.com';
var { Services } = require("resource://gre/modules/Services.jsm");
var { Cc, Cu, Ci} = require("chrome");
let cookieEnumerator = Services.cookies.getCookiesFromHost(domainToUse);
while (cookieEnumerator.hasMoreElements()) {
let cookie = cookieEnumerator.getNext().QueryInterface(Ci.nsICookie2);
console.log(cookie.host + ";" + cookie.name + "=" + cookie.value + "\n");
}
Update for newer versions of Firefox:
Note: At least by Firefox 50.0a2 (currently Firefox Developer Edition), it is necessary to use a slightly different call to getCookiesFromHost() to obtain the cookieEnumerator. Without the change, the call to getCookiesFromHost() will display a warning message in the Browser Console directing you to visit the nsICookieManager2 MDN documentation page which has no updated information on the warning, or any documentation on the change. I had to look in the source code to determine what was required. What appears to be desired is to pass in the current content document. However, from a background script that did not appear reasonable. The other way it is used is to just pass in an empty Object, {}. Thus, that line is changed to:
let cookieEnumerator = Services.cookies.getCookiesFromHost(domainToUse,{});
It is supposed to be for passing in "the originAttributes of cookies that would be be retrieved."
The above code is slightly modified from my answer to "How to set custom cookies using Firefox Add-on SDK (using Services from Firefox Add-on SDK)".
Could browser inside a machine obtain the machine's MAC address?
I'm building an API which need obtain unique identification of the machine (ideally, it could be MAC address), however, after discussion and research, I realize browsers don't support this. If not, any way the browser could obtain device related data which could be used to replace MAC address?
For IE and ActiveX allowed:
function networkInfo(){
var wmi = new ActiveXObject ("WbemScripting.SWbemLocator");
var service = wmi.ConnectServer(".");
e = new Enumerator(service.ExecQuery("SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = True"));
for(; !e.atEnd(); e.moveNext()) {
var s = e.item();
var macAddress = unescape(s.MACAddress);
}
return macAddress;
}
alert(networkInfo());
The Answer is no, a browser can't access the MAC address of a Device, with regular Js. However, have you explored Node JS? It has a Mac Plugin
that perhaps could be used in conjunction with another plugin called Browserify, Which could get you what you wanted. The benefit of using node is the massive amount of plugins that allow you to do things with js in your browser that you can't otherwise.
But you could create a unique UID on the page load, and save it somehow through localstorage, and pull that when you need a Device Specific ID. This won't work cross browser though. Hope this points you in the right direction. Good Luck.
The app I am working on, currently uses XML dataisland files to retrieve the dropdown data. Below is the code that defines the file.
<xml id="DefaultDataIslands" src="../XMLData/DataIslands-<%=((User.Identity).Database)%>.xml">
</xml>
Below is an example code that uses these XML dataislands.
var oDataIsland = document.getElementById("DefaultDataIslands");
var oXmlNodes = oDataIsland.XMLDocument.selectNodes("XMLDataIslands/DataIsland[#ID='DIMRGroup']/Option");
This oDataIsland line is used about 4k times total in the application. The application itself is intranet, so, I can even ask the users to download the xml files directly. Whole point is to keep the changes required to minimum, while removing all traces of XML tags. I want to make sure that application works on Chrome once this thing is completed.
I checked the link from mozilla regarding the dataislands here. https://developer.mozilla.org/en/docs/Using_XML_Data_Islands_in_Mozilla
Below is the code based on that mozilla link.
var doc = document.getElementById(strDataSource).contentDocument;
var mainNode = doc.getElementsByTagName("DataIsland");
var oXmlNodes;
var strOptions = "";
//finds the selected node based on the id, and gets the options for that id
for (i = 0; i < mainNode.length; i++) {
if (mainNode[i].getAttributeNode("ID").nodeValue == strDataMember) {
oXmlNodes = mainNode[i].getElementsByTagName("Option");
}
}
This code reads the data properly, works perfectly in IE (10 with standards mode, no quirks), was easy enough change to do in the full solution.
Only problem is, document.getElementById(strDataSource).contentDocument; line fails in Chrome. This is the same line as what was mentioned in Mozilla's documentation. But somehow contentDocument property is undefined on chrome.
So, I need some other suggestion on how to get this fixed. I tried other methods, using HTTPRequest (too many request per page), using JSON (requires changing existing methods completely), using backend to process XML instead of doing it client side (requires architectural changes). Till now, all these ideas failed.
Is there any other method that I can use? Or should I fix the contentDocument issue?
To allow contentDocument in Chrome, you will have to use --allow-file-access-from-files. Following are the steps for doing so:
Get the url of your Chrome Installation path to your chrome
installation e.g
C:\Users-your-user-name\AppData\Local\Google\Chrome\Application>
Launch the Google Chrome browser from the command line window with
the additional argument ‘–allow-file-access-from-files’. E.g ‘path
to your chrome installation\chrome.exe
--allow-file-access-from-files’
Temporary method you can use each time you are testing
Copy the existing chrome launcher
Do as above and save it with a new name e.g chrome - testing
Alternatively, you can simply create a new launcher with the above and use it to start chrome.
Source
We have a web application which runs in a kiosk mode Firefox, using the RKiosk extension to achieve this. We suspect that we have a very rare error in the system which yields in a JavaScript error. However because we can't access the JavaScript console we can't examine the log.
I'm searching for an option to make Firefox log all JavaScript console messages into a file regardless of the tab and page opened. I can't seem to find any extension for this. I'm already using log4javascript which sends errors back to the server, but it seems that our application crashes in a way that it skips the logging altogether.
Writing to a file sounds like a tedious task to me. It requires privileges that browser code doesn't normally have and you'd have to negotiate with an add-on you'd have to write in order to access file I/O.
From what I understand your issue is
I'd like to make Firefox log all errors
There are several approaches we can do to tackle this
First approach - log everything to localStorage too:
Now, rather than writing to an actual file, you can write to localStorage or IndexedDB instead.
localStorage["myApplog"] = localStorage["myApplog"] || "";
var oldLog = console.log;
console.log = function(){
oldLog.apply(console,arguments); // use the old console log
var message = "\n "+(new Date).toISOString() + " :: "+
Array.prototype.join.call(arguments," , "); // the arguments
localStorage["myApplog"] += message;
}
This is rather dirty and rather slow, but it should get the job done and you can access the log later in local storage. LocalStorage has a ~5MB limit if I recall correctly which I think is enough if you don't go crazy with logging. You can also run it selectively.
Second approach - log only errors
This is similar to what Pumbaa80 suggested. You can simply override window.onerror and only log errors.
// put an empty string in loggedWinErrors first
var oldError = window.onerror || function(){};
window.onerror = function(err,url,lineNumber){
oldError.call(this,err,url,lineNumber);
var err ="\n Error: (file: " + url+", error: "+err+", lineNumber: "+lineNumber+")");
localStorage["loggedWinErrors"] += err;
}
Third and drastic approach - use a VM.
This is the most powerful version, but it provides the most problematic user experience. You run the kiosk in a virtual machine, you detect an uncaught exception - when you do you freeze the machine and save its state, and run a backup VM instead. I've only had to do this when tackling the most fearsome errors and it's not pretty. Unless you really want the whole captured state - don't do this.
Really, do the extension before this - this is tedious but it gets very solid results.
In conclusion, I think the first approach or even just the second one are more than enough for what you need. localStorage is an abstracted storage that web pages get for saving state without security issues. If that's not big enough we can talk about an IndexedDB solution.
It all really depends on the use case you have.
You can use XULRunner...a Mozilla runtime environment for XUL applications. It uses Gecko like Firefox and:
You can access the file system or using the SQLite database to store logs.
You can render your kiosk in fullscreen mode without using extensions.
Have you tried jserrorcollector? We are using it and it works fine (only in Firefox). It's only for Java.
// Initialize
FirefoxProfile ffProfile = null;
ffProfile = new FirefoxProfile();
JavaScriptError.addExtension(ffProfile);
// Get the errors
List<JavaScriptError> jsErrors = JavaScriptError.readErrors(webDriver);
More information: https://github.com/mguillem/JSErrorCollector
Have you considered remote logging?
I commonly assign window.onerror to do send a request to a webserver storing the details of the error remotely. You could do the same with console.log if you preferred.
Try the following console export. It is a plugin for Firebug of Firefox. It's quite handy.
http://www.softwareishard.com/blog/consoleexport/
If you are able/willing to switch from Firefox to Chrome or Opera you would be able to use the Sandboxed Filesystem API to write a local file. See:
http://www.html5rocks.com/en/tutorials/file/filesystem/
http://caniuse.com/filesystem
Start in kiosk mode using chrome.exe --kiosk <url>
You would then want to disable Alt-F4 and Ctrl-Alt-Del which on Windows can be done with several third-party tools like Auto Hotkey (Disable Ctrl-Alt-Del Script).
You could use a remote logging script like Qbaka. It catches every JS error and sends it to the Qbaka server. There you can login and see all JS errors. Qbaka stores the exact error message, the script, line number, stack trace and the used browser for each error message.
So I'm toying around with HTML 5 and the localStorage and I'm noticing that my values only get stored when I run the page in Firefox on the local host (i.e. http://127.0.0.1:8000/test/index.html), but when I run the file locally (file:///C:/test/index.html) my values don't get stored. Safari 4 has no problems with both setups.
So does anybody know if this is by design -> DOM Storage on the Mozilla Developer Center
(Firefox 2 permitted access to storage
objects higher in the domain hierarchy
than the current document. This is no
longer allowed in Firefox 3, for
security reasons. In addition, this
proposed addition to HTML 5 has been
removed from the HTML 5 specification
in favor of localStorage, which is
implemented in Firefox 3.5.)
Or if there is a workaround?
I wonder because offline storage that works only online sounds silly :P
If anybody wonders, the code is as easy as it gets:
function save()
{
localStorage.setItem('foo','bar');
}
function load()
{
var test = localStorage.getItem('foo');
alert(test);
}
It seems a bug: Bug 507361 - localStorage doesn't work in file:/// documents
Hope is fixed soon!
2011-09-13: Bug fixed, implemented in 'Mozilla8'. I tested this with Firefox 8 and it works now.
Well, the linked document does say that
localStorage is the same as globalStorage[location.hostname], with the exception of being scoped to an HTML5 origin (scheme + hostname + non-standard port)
I don't want to claim that I understand 100% what that means, but the bit in brackets would suggest that the URL needs to have certain properties - in particular that the scheme and hostname are what Firefox considers an HTML 5 origin. I suspect that file:/// URLs don't match this, while your http://127.0.0.1/ does.
edit: Looking at the W3C's description of the Origin property, step 7 looks like it might be causing the problem. Depending on how the localStorage handling is implemented, it may be expecting a 3-tuple as returned by step 12, but for a file:// URL the return value may be just about anything.
So, er, I suppose it is by design. On reflection, chances are that this isn't really by design; there's no reason why localStorage shouldn't work for file:// URLs. It might just be a case of the output of one browser-specific implementation not matching the expectations of another.
As for workarounds, would globalStorage not do what you want here?
As of Oct 5 2020, localStorage on Firefox seems to be broken again. Try this:
Download Mozilla demo page: https://mdn.github.io/dom-examples/web-storage/
Change the animal/color to something other than default.
close the page's tab (or the browser).
Download the page again. It's back to defaults. (Firefox 81:0 et.al.)
Even worse, if you do step 1 & 2 above and then open another copy of the demo in a new tab, not only does the new tab not get the saved data, but the original demo page (refresh it) has gone back to the defaults; as though the new tab STEPPED on the saved data.