Custom HTML Dialog in Electron - html

How (or is it even possible) to use custom HTML dialogs in Electron? I know that Electron provides certain dialogs (showMessageDialog, showErrorDialog) but these do not seem to allow custom HTML.
I do not wish to use native HTML dialogs (dialog) tag as it does not 'blend in' with the user interface.
Any help would be much appreciated. Thanks!

You can create a BrowserWindow that's modal and, if you like, frameless. See http://electron.atom.io/docs/api/browser-window/.

Yes.
On your parent you should have:
const { remote } = require('electron');
const { BrowserWindow } = require('electron').remote;
and then:
let child = new BrowserWindow({
parent: remote.getCurrentWindow(),
modal: true,
width:300, height:300,
webPreferences: {
enableRemoteModule: true,
nodeIntegration: true
}
});
child.loadFile('myCustomModal.html');
On myCustomModal.html remeber to include a way to close the modal!
like:
<button id="cancel-btn">Cancel</button>
<script>
const remote = require('electron').remote;
document.getElementById("cancel-btn").addEventListener("click", function (e) {
var window = remote.getCurrentWindow();
window.close();
});
</script>

As Marc Rochkind said in a previous answer, you can use modal windows in Electron.
However, I have found a small bug with modal windows which causes the parent window to flicker for a very short duration when its .show() function is called. After quite some time on Google, I found an open issue on GitHub about the same problem. After reading the comment section in the issue, and stumbling across some code snippets, I shared a hacky solution in the issue's comment section.
It does take some work to set up, but once it's done, it's really easy to port to other child windows.

Related

How can I programmatically log out of Forge?

I followed this guide from the Forge Community Blog.
The blog suggests loading an iFrame with the src attribute set to https://accounts.autodesk.com/Authentication/LogOut
<iframe src="https://accounts.autodesk.com/Authentication/LogOut" />
Though the iFrame loads properly, the user does not get logged out of the Forge platform.
This method worked well until sometime this past week or so. Now, the user remains logged in.
However, manually opening a new window and navigating to the LogOut URL does log the user out.
This appears to be a new change but I cannot find any documentation for it.
I used this in the past and so far I have not encountered any issue, basically goes to the Nodejs SDK to use the endpoint for sign out.
// prepare sign out
$('#signOut').click(function () {
$('#hiddenFrame').on('load', function (event) {
location.href = '/api/forge/oauth/signout';
});
$('#hiddenFrame').attr('src', 'https://accounts.autodesk.com/Authentication/LogOut');
// learn more about this signout iframe at
// https://forge.autodesk.com/blog/log-out-forge
})
To solve this, I decided to open a temporary new window for the logout url. I'm not happy with the solution, but it functions.
const newWindow = open('https://accounts.autodesk.com/Authentication/LogOut');
setTimeout(() => newWindow.close(), 500);

Google apps script and jquery mobile loader giving two spinners

Let me preface this by saying I want a spinner...
I don't necessarily care whether it loads when the page first starts up, or later. The problem I'm experiencing also doesn't seem to care, as I've tried it both ways.
Right this moment, I don't declare it at the top of the page. Because I have a lot of visualization stuff going on, I start that up and immediately pass some info to the spinner (which also starts it up):
google.load('visualization', '1', {packages:['controls'], callback: initializeTables});
function initializeTables() {
provideInfo("loading proficiencies (Step 1/12)");
//etc... }
function provideInfo(text) {
$.mobile.loading( "show", {
text: text,
textVisible: true
});
}
So that starts... fine... ish...
The problem is that there's actually two spinners started when that starts - one in front, one behind. Because the one in front is slightly offset from the one behind, I can see both.
If I later call:
$.mobile.loading( "hide" );
It only hides the front one, not the back one.
I've found I can hide both by saying:
$(".ui-loader").hide();
Which is great. But, I'd like to not see two in the first place. I've tried to puzzle out the jquery mobile documentation page, to no avail (it also mentions a "global method docs" but I haven't been able to find that link):
//This does not work:
$( ".ui-loader" ).loader( "option", "text", "Loading Page..." );
//Nor does this:
$( "#notify_div" ).loader( "show" );
$( "#notify_div" ).loader( "option", "text", "Loading Page..." );
Anyone know how to get it all into one spinner, or why it's loading two?
Sadly, the current JQM documentation is for the 1.5 version which hasn't be released yet. You need to look directly at the source code of the 1.4.5 version.
There is a JQM default which is showing the spinner when a page is loading. You can override this behavior at JQM initialization.
<script type="application/javascript" src="js/jquery-2.2.4.js"></script>
<script>
$(document).on("mobileinit", function () {
$.mobile.changePage.defaults.showLoadMsg = false;
});
</script>
<script type="application/javascript" src="js/jquery.mobile-1.4.5.js"></script>
If You look at line 5847 of the JQM uncompressed source code, You will find all the configurable settings for that.
Moreover, just for the sake of completeness, there is another setting where You can tell JQM to not show the spinner for already cached pages. Just look at line 5122 of the JQM uncompressed source code:
// This delay allows loads that pull from browser cache to
// occur without showing the loading message.
loadMsgDelay: 50
Hope this help.

ZoomWindow extension breaks without GUI?

Using v2.13 of the viewer, the ZoomWindow extension relies on having the default GUI enabled. Is there a way around this? The load method is:
proto.load = function() {
var viewer = this.viewer;
var toolbar = viewer.getToolbar(true);
//var toolbar = viewer.getToolbar ? viewer.getToolbar(true) : undefined;
// Init & Register tool
this.tool = new namespace.ZoomWindowTool(viewer);
viewer.toolController.registerTool(this.tool);
// Add the ui to the viewer.
this.createUI(toolbar);
return true;
};
which fails because getToolbar is undefined.
It seems from the commented out line that this has been considered, but not implemented.
What is the best way to implement a work around - should I copy the entire extension with a new name, or can I replace the load method at runtime?
Edit: was looking to use the headless viewer, but it seems easiest just to hide the UI with css.
It's not clear to me if you are using the GuiViewer3D or want to use the Viewer3D, the viewer without Autodesk custom UI. If you use GuiViewer3D, you can simply wait for the toolbar to be loaded before loading the ZoomWindow extension, which requires the toolbar controls to be created in order to add a button to it.
viewer.addEventListener(Autodesk.Viewing.TOOLBAR_CREATED_EVENT, function () {
viewer.loadExtension('Autodesk.Viewing.ZoomWindow')
})
Here is a blogpost I wrote a while ago about using events in the viewer. It is not up-to-date with the current version but remains valid:
http://adndevblog.typepad.com/cloud_and_mobile/2015/10/event-watcher-extension-for-view-data.html
Now as Zhong mentioned, if you want to use the headless viewer with no UI and still use the extension, you may have to copy and customize it as you suggested. But an easier workaround could be to use GuiViewer3D and simply hide the existing toolbar with css, so the the js code remains valid. Set display:none on div id="guiviewer3d-toolbar", for example, or on the adsk-control class.
Hope that helps

Video.js - preventing click-to-play functionality

I'm using video.js to embed a video into an HTML page. It is to be used as a ipad-only web app so I believe that it's using the native HTML5 player. I'm trying to disable the click-to-play functionality (so that the user must use the controls) but I am having trouble doing so.
I've tried unbinding the click event (using jQuery) form the video/video player/poster and I've tried using addevent to add e.preventDefault() to the video but none of this seems to work.
Ps. I found a couple of posts saying you could comment out a line in the code, but this line doesn't exist in my version - maybe the plugin has been rewritten.
Check here
https://github.com/videojs/video.js/blob/master/docs/api/vjs.MediaTechController.md#removecontrolslisteners
So for example
v = videojs('scene04-video');
v.tech.removeControlsListeners();
You can try this. It helped me. Just add this to css file:
.video-js.vjs-playing .vjs-tech {
pointer-events: none;
}
It would be helpful to know which version you are using. This works for me on 4.1 (latest api)
// Disable big-play-button
videojs.Player.prototype.options_.children.bigPlayButton = false;
// Override click handler on media object;
videojs.MediaTechController.prototype.onClick = function() {};
// Initialize video
var vid = videojs("video", {});
// Show controls (since in my browser it doesn't think it needs to inititally)
vid.controlBar.show();
UPDATE: I should clarify that the above only works using the dev.js API (not the prod/minified version). In the minified version, the MediaTechController's onClick function name isn't preserved, you can't reliably override it. In this case, you can try manually disconnecting the the HTML5 and Flash click events:
videojs.Html5.off('click');
videojs.Flash.off('click');
var vid = videojs("video", {}, function() {
this.bigPlayButton.hide();
});
// Again - show the controlbar (optionally)
vid.controlBar.show();
Check this:
.vjs-tech {
pointer-events: none;
}

How do I access the popup page DOM from bg page in Chrome extension?

In Google Chrome's extension developer section, it says
The HTML pages inside an extension
have complete access to each other's
DOMs, and they can invoke functions on
each other. ... The popup's contents
are a web page defined by an HTML file
(popup.html). The popup doesn't need
to duplicate code that's in the
background page (background.html)
because the popup can invoke functions
on the background page
I've loaded and tested jQuery, and can access DOM elements in background.html with jQuery, but I cannot figure out how to get access to DOM elements in popup.html from background.html.
can you discuss why you would want to do that? A background page is a page that lives forever for the life time of your extension. While the popup page only lives when you click on the popup.
In my opinion, it should be refactored the other way around, your popup should request something from the background page. You just do this in the popup to access the background page:
chrome.extension.getBackgroundPage()
But if you insist, you can use simple communication with extension pages with sendRequest() and onRequest. Perhaps you can use chrome.extension.getViews
I understand why you want to do this as I have run into the problem myself.
The easiest thing I could think of was using Google's method of a callback - the sendRequest and onRequest methods work as well, but I find them to be clunky and less straightforward.
Popup.js
chrome.extension.getBackgroundPage().doMethod(function(params)
{
// Work with modified params
// Use local variables
});
Background.html
function doMethod(callback)
{
if(callback)
{
// Create/modify params if needed
var params;
// Invoke the callback
callback(params);
}
}
As other answers mention, you can call background.js functions from popup.js like so:
var _background = chrome.extension.getBackgroundPage();
_background.backgroundJsFunction();
But to access popup.js or popup.html from background.js, you're supposed to use the messages architecture like so:
// in background.js
chrome.runtime.sendMessage( { property: value } );
// in popup.js
chrome.runtime.onMessage.addListener(handleBackgroundMessages);
function handleBackgroundMessages(message)
{
if (message.property === value)
// do stuff
}
However, it seems that you can synchronously access popup.js from background.js, just like you can synchronously access the other way around. chrome.extension.getViews can get you the popup window object, and you can use that to call functions, access variables, and access the DOM.
var _popup = chrome.extension.getViews( { type: 'popup' } )[0];
_popup.popupJsFunction();
_popup.document.getElementById('element');
_popup.document.title = 'poop'
Note that getViews() will return [] if the popup is not open, so you have to handle that.
I'm not sure why no one else mentioned this. Perhaps there's some pitfalls or bad practices to this that I've overlooked? But in my limited testing in my own extension, it seems to work.