neutralinojs workaround to HTML input attribute accept - neutralinojs

I have a neutralinojs app with an file input. It should only be possible to choose files from type ".csv" or ".xlsx". So I use the accept attribute.
<input type="file" accept=".csv,.xlsx" />
That works in browser mode but not in window mode.
Is there a workaround to show only files with these filetypes in the file chooser?

You Need To Use Neutralino's API For Dialogs.
So In Neutralino's OS API We Have Some Functions For save file, open file and open folder using which we can show dialogs to users.
In your case you need to use open file dialog so you can use Neutralino.os.showOpenDialog, example:
Neutralino.os.showOpenDialog('Open a file', {
filters: [
{name: 'Documents', extensions: ['csv', 'xlsx']},
{name: 'All files', extensions: ['*']}
]
}).then(result => {
console.log('You have selected:', result);
});
One thing to note is all these API will work in both modes, browser and window.
So if you run this code in browser mode a dialog box will still appear.
Read More About Neutralino's OS APIs

Related

Silent printing in electron

I am currently building an electron app. I have a PDF on my local file system which I need to silently print out (on the default printer). I came across the node-printer library, but it doesn't seem to work for me. Is there an easy solution to achieve this?
Well first of all it is near impossible to understand what you mean with "silent" print. Because once you send a print order to your system printer it will be out of your hand to be silent at all. On Windows for example once the order was given, at least the systemtray icon will indicate that something is going on. That said, there are very good described features for printing with electron even "silent" is one of them:
You need to get all system printers if you do not want to use the default printer:
contents.getPrinters()
Which will return a PrinterInfo[] Object.
Here is an example how the object will look like from the electron PrtinerInfo Docs:
{
name: 'Zebra_LP2844',
description: 'Zebra LP2844',
status: 3,
isDefault: false,
options: {
copies: '1',
'device-uri': 'usb://Zebra/LP2844?location=14200000',
finishings: '3',
'job-cancel-after': '10800',
'job-hold-until': 'no-hold',
'job-priority': '50',
'job-sheets': 'none,none',
'marker-change-time': '0',
'number-up': '1',
'printer-commands': 'none',
'printer-info': 'Zebra LP2844',
'printer-is-accepting-jobs': 'true',
'printer-is-shared': 'true',
'printer-location': '',
'printer-make-and-model': 'Zebra EPL2 Label Printer',
'printer-state': '3',
'printer-state-change-time': '1484872644',
'printer-state-reasons': 'offline-report',
'printer-type': '36932',
'printer-uri-supported': 'ipp://localhost/printers/Zebra_LP2844',
system_driverinfo: 'Z'
}
}
To print your file you can do it with
contents.print([options])
The options are descriped in the docs for contents.print():
options Object (optional):
silent Boolean (optional) - Don’t ask user for print settings. Default is false.
printBackground Boolean (optional) - Also prints the background color and image of the web page. Default is false.
deviceName String (optional) - Set the printer device name to use. Default is ''.
Prints window’s web page. When silent is set to true, Electron will pick the system’s default printer if deviceName is empty and the default settings for printing.
Calling window.print() in web page is equivalent to calling webContents.print({silent: false, printBackground: false, deviceName: ''}).
Use page-break-before: always; CSS style to force to print to a new page.
So all you need is to load the PDF into a hidden window and then fire the print method implemented in electron with the flag set to silent.
// In the main process.
const {app, BrowserWindow} = require('electron');
let win = null;
app.on('ready', () => {
// Create window
win = new BrowserWindow({width: 800, height: 600, show: false });
// Could be redundant, try if you need this.
win.once('ready-to-show', () => win.hide())
// load PDF.
win.loadURL(`file://directory/to/pdf/document.pdf`);
// if pdf is loaded start printing.
win.webContents.on('did-finish-load', () => {
win.webContents.print({silent: true});
// close window after print order.
win = null;
});
});
However let me give you a little warning:
Once you start printing it can and will get frustrating because there are drivers out there which will interpret data in a slightly different way. Meaning that margins could be ignored and much more. Since you already have a PDF this problem will most likely not happen. But keep this in mind if you ever want to use this method for example contents.printToPDF(options, callback). That beeing said there are plently of options to avoid getting frustrated like using a predefined stylesheet like descriped in this question: Print: How to stick footer on every page to the bottom?
If you want to search for features in electron and you do not know where they could be hidden, all you have to do is to go to "all" docs and use your search function: https://electron.atom.io/docs/all/
regards,
Megajin
I recently published NPM package to print PDF files from Node.js and Electron. You can send a PDF file to the default printer or to a specific one. Works fine on Windows and Unix-like operating systems: https://github.com/artiebits/pdf-to-printer.
It's easy to install, just (if using yarn):
yarn add pdf-to-printer
or (if using npm):
npm install --save pdf-to-printer
Then, to silently print the file to the default printer you do:
import { print } from "pdf-to-printer";
print("assets/pdf-sample.pdf")
.then(console.log)
.catch(console.error);
To my knowledge there is currently no way to do this directly using Electron because while using contents.print([]) does allow for 'silently' printing HTML files, it isn't able to print PDF views. This is currently an open feature request: https://github.com/electron/electron/issues/9029
Edit: I managed to work around this by converting the PDF to a PNG and then using Electron's print functionality (which is able to print PNGs) to print the image based view. One of the major downsides to this is that all of the PDF to PNG/JPEG conversion libraries for NodeJS have a number of dependencies, meaning I had to implement them in an Express server and then have my Electron app send all PDFs to the server for conversion. It's not a great option, but it does work.

Remove terminal icon in node notifier

I am using the https://github.com/mikaelbr/node-notifier package to show notifications in shell.
This is my code:
var notifier = require('node-notifier');
var path = require('path');
notifier.notify({
title: 'My awesome title',
message: 'Hello from node, Mr. User!',
icon: path.join(__dirname, 'coulson.jpg'), // absolute path (not balloons)
sound: true, // Only Notification Center or Windows Toasters
wait: true // wait with callback until user action is taken on notification
}, function (err, response) {
// response is response from notification
});
notifier.on('click', function (notifierObject, options) {
// Happens if `wait: true` and user clicks notification
});
notifier.on('timeout', function (notifierObject, options) {
// Happens if `wait: true` and notification closes
});
The notification comes like this:
As you can see a terminal icon is coming before the name.
Can you help me how to remove that icon?
It is known issue with node-notifier.
From issue #71:
mikaelbr:
No, I'm afraid that's how the notification work, as it's the terminal that initiates the message. The only way to avoid this is to use your custom terminal-notifier where the Terminal icon is swapped for your own. It's not a big task, and you can easily set customPath for notification center reporter.
kurisubrooks:
This happens because of the way notifications in OS X work. The notification will show the referring app icon, and because we're using terminal-notifier to push notifications, we have the icon of terminal-notifier.
To work around this, you'll need to compile terminal-notifier with your own app.icns. Download the source, change out the AppIcon bundle with your own in Xcode, recompile terminal-notifier and pop it into node-notifier. (/node-notifier/vendor/terminal-notifier.app)
Now that you have your own terminal-notifier inside node-notifier, remove all the icon references from your OS X Notification Center code, and run the notification as if it has no icon. If the old app icon is showing in your notifications, you need to clear your icon cache. (Google how to do this)
Another valuable comment from mikaelb:
That's correct. But keep in mind, node-notifier uses a fork of terminal-notifier (github.com/mikaelbr/terminal-notifier) to add option to wait for notification to finish, so this should be used to add your own icon. A easy way to do it is to copy/paste from the vendor-folder and use customPath to point to your own vendor.
I tried #Aleksandr M's steps but it didn't seem to work for me. Maybe I didn't understand the steps well enough. Here's how it worked for me.
I cloned https://github.com/mikaelbr/terminal-notifier . Then opened the project with xcode and deleted the Terminal.icns file and replaced it with my custom icon Myicon.icns.
Then edited terminal-notifier/Terminal Notifier/Terminal Notifier-Info.plist by setting the key icon file to Myicon.
After doing this, simply building the project did NOT work. I had to change the values of the build version and build identifier (any new value would do) see this.
Afterwards I just built the project with xcode and then copied the built .app file (you can find it by clicking the Products directory of the project from xcode Products > right click the file > show in finder) to my electron project
e.g your final path may look like this. electron-project/vendor/terminal-notifier.app.
Then I set customPath as #Aleksandr M suggested.
Here's what mine looked like
var notifier = new NotificationCenter({
customPath: 'vendor/terminal-notifier.app/Contents/MacOS/terminal-notifier'
});
And THEN it worked! 🙂
This solved my problem and you only need to have your icns file ready:
run this command in terminal after downloading :customise-terminal-notifier
** path/customise-terminal-notifier-master/customise-terminal-notifier -i path/Terminal.icns -b com.bundle.identifier

Unable to open local file using cordova inappbrowser on windows 8.1 platform

I am developing a phone gap application and we've recently added support for the windows 8.1 platform. The application downloads/creates files which are saved to the device using the Cordova FileSystem API.
I have successfully saved a file to the device using a URL which looks like this
ms-appdata:///local/file.png
I have checked on my PC and the file is viewable inside the LocalState folder under the app's root folder. However, when I try to open this file using inAppBrowser nothing happens; no error message is being reported and none of the inAppBrowser default events fire.
function empty() { alert('here'); } //never fires
var absoluteUrl = "ms-appdata:///local/file.png";
cordova.InAppBrowser.open(absoluteURL, "_blank", "location=no", { loadstart: empty, loadstop: empty, loaderror: empty });
I have verified that the url is valid by calling the following built-in javascript on the url
Windows.Storage.StorageFile.getFileFromApplicationUriAsync(uri).done(function (file) {
debugger; //the file object contains the correct path to the file; C:\...etc.
});
Also, adding the url as the src for an img tag works as expected.
I have also tried attaching the inAppBrowser handlers using addEventListener("loadstart") etc. but none of them are firing either. However, when I try to open "http://www.google.com" the events do fire and the inAppBrowser pops up on the screen.
After inspecting the dom I can see that the inAppBrowser element has been added, but it doesn't appear to have a source attribute set
<div class="inAppBrowserWrap">
<x-ms-webview style="border-width: 0px; width: 100%; height: 100%;"></x-ms-webview>
</div>
I have looked at other questions such as this one but to no avail. I have verified that
a) InAppBrowser is installed
b) deviceReady has fired
I have also tried changing the target to "_self" (same issue) and "_system" (popup saying you need a new app to open a file of type msappdata://) and I'm running out of ideas. Has anybody come across similar issues?
I had a similar problem. My cordova app downloads a file and then opens it with native browser (so that images, PDF files and so on are properly handled).
In the end I had to modify InAppBrowserProxy.js class (part of InAppBrowser plugin for Windows platform).
This is the code that opens the file (plain JavaScript):
// This value comes from somewhere, I write it here as an example
var path = 'ms-appdata:///local//myfile.jpg';
// Open file in InAppBrowser
window.open(path, '_system', 'location=no');
Then, I updated InAppBrowserProxy.js file (under platforms\windows\www\plugins\cordova-plugin-inappbrowser\src\windows). I replaced this code fragment:
if (target === "_system") {
url = new Windows.Foundation.Uri(strUrl);
Windows.System.Launcher.launchUriAsync(url);
}
By this:
if (target === "_system") {
if (strUrl.indexOf('ms-appdata:///local//') == 0) {
var fileName = decodeURI(strUrl.substr(String(strUrl).lastIndexOf("/") + 1));
var localFolder = Windows.Storage.ApplicationData.current.localFolder;
localFolder.getFileAsync(fileName).then(function (file) {
Windows.System.Launcher.launchFileAsync(file);
}, function (error) {
console.log("Error getting file '" + fileName + "': " + error);
});
} else {
url = new Windows.Foundation.Uri(strUrl);
Windows.System.Launcher.launchUriAsync(url);
}
}
This is a very ad-hoc hack, but it did the trick for me, and it could be improved, extended, and even standarized.
Anyway, there may be other ways to achieve this, it's just that this worked for me...
After more searching, it seems that the x-ms-webview, which is the underlying component used by PhoneGap for Windows only supports loading HTML content. This Microsoft blog post on the web view control states that
UnviewableContentIdentified – Is fired when a user navigates to
content other than a webpage. The WebView control is only capable of
displaying HTML content. It doesn’t support displaying standalone
images, downloading files, viewing Office documents, etc. This event
is fired so the app can decide how to handle the situation.
This article suggests looking at the Windows.Data.Pdf namespace for providing in-app support for reading PDFs.

Chrome Extension: chrome.storage is undefined

I added the following code to my otherwise-working Google Chrome Extension…
var storage = chrome.storage ;
console.log("storage is " + storage) ;
var bookmarks = chrome.bookmarks ;
console.log("bookmarks is " + bookmarks) ;
Upon running, the console says
storage is undefined
bookmarks is [object Object]
In other words, bookmarks works OK but storage is missing in action. My manifest has requested both…
{
...
"permissions": [ "bookmarks", "tabs", "storage" ],
}
In case it matters, this extension is installed as an External Extension on Mac OS X. To make sure it was updated correctly, I copied the code above from the files installed into ~/Library/Application Support/Google/Chrome/Default/Extensions. And, of course, I've relaunched Chrome.
Why might chrome.storage be undefined?
Edit: the answer below was written in 2013. Now in 2021, as
Irfan wrote in comment:
chrome.storage is available from content script too. Your extension's
content scripts can directly access user data without the need for a
background page. https://developer.chrome.com/docs/extensions/reference/storage/
Original answer:
LocalStorage is only available in background pages and popup. If you need to acces to some data you will need to pass a message from your current page to a background page. Here is the code :
In your current page:
chrome.extension.sendMessage({action:"getstorage"}, function(response){
console.log("storage is " + response.myVar);
});
In the background page:
chrome.extension.onMessage.addListener(function(request, sender, sendResponse) {
if (request.action == "focusWindow"){
sendResponse({myVar: localStorage.myStorage});
}
});
You can find more examples in the chrome documentation on Message Passing
There is "Reload (Ctrl+R)" link inside extension on "Extensions" tab, clicking on it fixes the problem (I spent few hours). Nor disabling/enabling extension neither restarting Chrome browser will fix the problem. I hope it will save someone's time ;)

Chrome extension: Attaching current tab to popup and then going through its DOM

I'm in the process of making a Google Chrome extension, and encountered a problem.
I'm trying to upload and search through the DOM inside the popup.html.
Here is how I get the current tab (I found the script somewhere, credit doesn't belong to me):
chrome.windows.getCurrent(function(w) {
chrome.tabs.getSelected(w.id,function (response){
)};
My problem is this: I need to traverse through the DOM of the response. When trying to do so manually, I couldn't, as the response variable was now undefined for some reason, so using the Console isn't an option.
When trying to alert the response in the html file, it came as a object. Then, I tried to navigate through the response as if it has been the 'document' object, but no luck either.
Any help will be appreciated greatly.
You can get the selected tab for your popup by passing null as the window id to getSelected. () In your popup you can listen for extension events and execute a script to push the content to your popup:
chrome.extension.onRequest.addListener(
function(request, sender, sendResponse) {
if (request.action == "content")
{
console.log('content is ' + request.content.length + ' bytes');
}
});
chrome.tabs.getSelected(null, function(tab) {
chrome.tabs.executeScript(tab.id, { file: 'scripts/SendContent.js' } );
});
And finally the content script... I have it as "scripts/SendContent.js" in my extension folder, but the script is simple enough you could execute it by putting the code in the code property instead of the name in the file property of the object you pass to executeScript:
console.log('SendContent.js');
chrome.extension.sendRequest( {
action: "content",
host: document.location.hostname,
content: document.body.innerHTML
}, function(response) { }
);
Result:
POPUP: content is 67533 bytes
If you're having trouble, use console.log() and right-click on your page or browser action to inspect it and read your messages on the console (or debug your script from there).
I believe popups are sandboxed the same way that background pages are, so you'll need to use a content script to access the page DOM.
You can inject a content script with chrome.tabs.executeScript, handle your DOM traversal in the content script, then pass back the information you need from the content script to the popup using the message passing API.
I can try to elaborate on this if you give more information about the problem you're trying to solve.

Resources